diff --git a/DEPS b/DEPS index da5b85f..1821c2a 100644 --- a/DEPS +++ b/DEPS
@@ -149,7 +149,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '45faa0849352bb3c2f6ee6fa28cf91b790607d99', + 'swiftshader_revision': '3ed33cee5e61f854c36fb44b7253dda3052ff5ce', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -196,7 +196,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'ccc29087522abefc852d1294595ae6db7e86d649', + 'catapult_revision': 'dc658bb37c70d3153cda3e9993a3874ccd8871a9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -260,7 +260,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'aa9d6ad09d0d43ad2a35263fb45c272f40f95937', + 'dawn_revision': '8c1a90199a43f04f86539141b394f05014cea77a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -435,7 +435,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'c2575332bb4bee4a0e8330765cb8e8980bb554ec', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '4dc42cedf3ed6cc91ad1c99092d62991180bc0d1', 'condition': 'checkout_ios', }, @@ -752,7 +752,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a6918d7b72a9b0c1ff2c41d9515e14ec72256f93', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '28dfd94b57ae4aca22c40a3521fb6480d1c155be', 'condition': 'checkout_linux', }, @@ -777,7 +777,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ffb1ffb8228460b9c495216507daa90717c6193a', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cc43111eb273d5f660e6913970fa5da314c8b988', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1010,7 +1010,7 @@ }, 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + 'd64e328624e09cbc36e7077598bf0ff367dcdb4c', + Var('chromium_git') + '/webm/libvpx.git' + '@' + '8256c8b297c8b7c7ee4de24edff82ed67d6ef207', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1', @@ -1119,7 +1119,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c0eace27e740347e63d7730ee9b4eba492e7ea1e', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '282b28c1234c109a45003a5470512982177e77c1', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1334,7 +1334,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5b257f91fc81cfb1633b415deca73312a57947fa', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7e53cb9263b40dd836a58e0ae548e8a24d98905f', 'condition': 'checkout_src_internal', },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 59aaaad..8943046 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -678,6 +678,7 @@ 'build/android/gyp/generate_linker_version_script.pydeps', 'build/android/gyp/ijar.pydeps', 'build/android/gyp/java_cpp_enum.pydeps', + 'build/android/gyp/java_cpp_strings.pydeps', 'build/android/gyp/javac.pydeps', 'build/android/gyp/jinja_template.pydeps', 'build/android/gyp/lint.pydeps',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index dd22654..8dc38b91 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc
@@ -294,8 +294,6 @@ content::BackgroundFetchDelegate* AwBrowserContext::GetBackgroundFetchDelegate() { - // TODO(crbug.com/766077): Resolve whether to support or disable background - // fetch on WebView. return nullptr; }
diff --git a/android_webview/browser/gfx/browser_view_renderer.cc b/android_webview/browser/gfx/browser_view_renderer.cc index d61008b..9e13c46 100644 --- a/android_webview/browser/gfx/browser_view_renderer.cc +++ b/android_webview/browser/gfx/browser_view_renderer.cc
@@ -161,10 +161,12 @@ if (g_memory_override_in_bytes) { bytes_limit = static_cast<size_t>(g_memory_override_in_bytes); } else { - gfx::Rect interest_rect = - offscreen_pre_raster_ || external_draw_constraints_.is_layer - ? gfx::Rect(size_) - : last_on_draw_global_visible_rect_; + // Note we are using |last_on_draw_global_visible_rect_| rather than + // |external_draw_constraints_.viewport_size|. This is to reduce budget + // for a webview that's much smaller than the surface it's rendering. + gfx::Rect interest_rect = offscreen_pre_raster_ + ? gfx::Rect(size_) + : last_on_draw_global_visible_rect_; size_t width = interest_rect.width(); size_t height = interest_rect.height(); bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height; @@ -226,35 +228,24 @@ gfx::Transform transform_for_tile_priority = external_draw_constraints_.transform; - gfx::Rect viewport_rect_for_tile_priority = - ComputeViewportRectForTilePriority(); + // Do not override (ie leave empty) for offscreen raster. + gfx::Size viewport_size_for_tile_priority = + offscreen_pre_raster_ ? gfx::Size() + : external_draw_constraints_.viewport_size; scoped_refptr<content::SynchronousCompositor::FrameFuture> future = - compositor_->DemandDrawHwAsync(size_, viewport_rect_for_tile_priority, + compositor_->DemandDrawHwAsync(size_, + gfx::Rect(viewport_size_for_tile_priority), transform_for_tile_priority); std::unique_ptr<ChildFrame> child_frame = std::make_unique<ChildFrame>( - std::move(future), compositor_id_, - viewport_rect_for_tile_priority.IsEmpty(), transform_for_tile_priority, - offscreen_pre_raster_, external_draw_constraints_.is_layer); + std::move(future), compositor_id_, viewport_size_for_tile_priority, + transform_for_tile_priority, offscreen_pre_raster_); ReturnUnusedResource( current_compositor_frame_consumer_->SetFrameOnUI(std::move(child_frame))); return true; } -gfx::Rect BrowserViewRenderer::ComputeViewportRectForTilePriority() { - // If the WebView is on a layer, WebView does not know what transform is - // applied onto the layer so global visible rect does not make sense here. - // In this case, just use the surface rect for tiling. - // Leave viewport_rect_for_tile_priority empty if offscreen_pre_raster_ is on. - gfx::Rect viewport_rect_for_tile_priority; - - if (!offscreen_pre_raster_ && !external_draw_constraints_.is_layer) { - viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_; - } - return viewport_rect_for_tile_priority; -} - void BrowserViewRenderer::OnParentDrawConstraintsUpdated( CompositorFrameConsumer* compositor_frame_consumer) { DCHECK(compositor_frame_consumer);
diff --git a/android_webview/browser/gfx/browser_view_renderer.h b/android_webview/browser/gfx/browser_view_renderer.h index 1919ccd..24d2fff 100644 --- a/android_webview/browser/gfx/browser_view_renderer.h +++ b/android_webview/browser/gfx/browser_view_renderer.h
@@ -179,7 +179,6 @@ void ReturnResourceFromParent( CompositorFrameConsumer* compositor_frame_consumer); void ReleaseHardware(); - gfx::Rect ComputeViewportRectForTilePriority(); gfx::Vector2d max_scroll_offset() const;
diff --git a/android_webview/browser/gfx/browser_view_renderer_unittest.cc b/android_webview/browser/gfx/browser_view_renderer_unittest.cc index 7b084b1..b183f35 100644 --- a/android_webview/browser/gfx/browser_view_renderer_unittest.cc +++ b/android_webview/browser/gfx/browser_view_renderer_unittest.cc
@@ -162,8 +162,10 @@ TestAnimateInAndOutOfScreen() : on_draw_count_(0), draw_gl_count_on_rt_(0) {} void StartTest() override { - new_constraints_ = ParentCompositorDrawConstraints( - false, gfx::Transform(), window_->surface_size().IsEmpty()); + initial_constraints_ = ParentCompositorDrawConstraints( + window_->surface_size(), gfx::Transform()); + new_constraints_ = ParentCompositorDrawConstraints(window_->surface_size(), + gfx::Transform()); new_constraints_.transform.Scale(2.0, 2.0); browser_view_renderer_->PostInvalidate(ActiveCompositor()); } @@ -212,12 +214,7 @@ bool DrawConstraintsEquals( const ParentCompositorDrawConstraints& constraints1, const ParentCompositorDrawConstraints& constraints2) { - if (constraints1.is_layer != constraints2.is_layer || - constraints1.transform != constraints2.transform) - return false; - - return !constraints1.is_layer || - constraints1.surface_rect_empty == constraints2.surface_rect_empty; + return constraints1 == constraints2; } void OnParentDrawConstraintsUpdated() override {
diff --git a/android_webview/browser/gfx/child_frame.cc b/android_webview/browser/gfx/child_frame.cc index 9855691..1aeb95a 100644 --- a/android_webview/browser/gfx/child_frame.cc +++ b/android_webview/browser/gfx/child_frame.cc
@@ -14,17 +14,14 @@ ChildFrame::ChildFrame( scoped_refptr<content::SynchronousCompositor::FrameFuture> frame_future, const CompositorID& compositor_id, - bool viewport_rect_for_tile_priority_empty, + const gfx::Size& viewport_size_for_tile_priority, const gfx::Transform& transform_for_tile_priority, - bool offscreen_pre_raster, - bool is_layer) + bool offscreen_pre_raster) : frame_future(std::move(frame_future)), compositor_id(compositor_id), - viewport_rect_for_tile_priority_empty( - viewport_rect_for_tile_priority_empty), + viewport_size_for_tile_priority(viewport_size_for_tile_priority), transform_for_tile_priority(transform_for_tile_priority), - offscreen_pre_raster(offscreen_pre_raster), - is_layer(is_layer) {} + offscreen_pre_raster(offscreen_pre_raster) {} ChildFrame::~ChildFrame() { }
diff --git a/android_webview/browser/gfx/child_frame.h b/android_webview/browser/gfx/child_frame.h index aeb839a..483e63db 100644 --- a/android_webview/browser/gfx/child_frame.h +++ b/android_webview/browser/gfx/child_frame.h
@@ -11,6 +11,7 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" #include "content/public/browser/android/synchronous_compositor.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/transform.h" namespace viz { @@ -24,10 +25,9 @@ ChildFrame( scoped_refptr<content::SynchronousCompositor::FrameFuture> frame_future, const CompositorID& compositor_id, - bool viewport_rect_for_tile_priority_empty, + const gfx::Size& viewport_size_for_tile_priority, const gfx::Transform& transform_for_tile_priority, - bool offscreen_pre_raster, - bool is_layer); + bool offscreen_pre_raster); ~ChildFrame(); // Helper to move frame from |frame_future| to |frame|. @@ -40,10 +40,9 @@ std::unique_ptr<viz::CompositorFrame> frame; // The id of the compositor this |frame| comes from. const CompositorID compositor_id; - const bool viewport_rect_for_tile_priority_empty; + const gfx::Size viewport_size_for_tile_priority; const gfx::Transform transform_for_tile_priority; const bool offscreen_pre_raster; - const bool is_layer; private: DISALLOW_COPY_AND_ASSIGN(ChildFrame);
diff --git a/android_webview/browser/gfx/hardware_renderer.cc b/android_webview/browser/gfx/hardware_renderer.cc index bf7baa6..5d598107 100644 --- a/android_webview/browser/gfx/hardware_renderer.cc +++ b/android_webview/browser/gfx/hardware_renderer.cc
@@ -12,6 +12,7 @@ #include "android_webview/browser/gfx/parent_compositor_draw_constraints.h" #include "android_webview/browser/gfx/render_thread_manager.h" #include "android_webview/browser/gfx/surfaces_instance.h" +#include "base/macros.h" #include "base/trace_event/trace_event.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" @@ -143,8 +144,7 @@ // Need to post the new transform matrix back to child compositor // because there is no onDraw during a Render Thread animation, and child // compositor might not have the tiles rasterized as the animation goes on. - ParentCompositorDrawConstraints draw_constraints(params->is_layer, transform, - viewport.IsEmpty()); + ParentCompositorDrawConstraints draw_constraints(viewport, transform); if (!child_frame_.get() || draw_constraints.NeedUpdate(*child_frame_)) { render_thread_manager_->PostExternalDrawConstraintsToChildCompositorOnRT( draw_constraints); @@ -159,6 +159,8 @@ surfaces_->DrawAndSwap(viewport, clip, transform, surface_size_, viz::SurfaceId(frame_sink_id_, child_id_), device_scale_factor_, params->color_space); + // TODO(crbug.com/938956): Implement presentation feedbacks. + ignore_result(support_->TakePresentationFeedbacks()); } void HardwareRenderer::AllocateSurface() {
diff --git a/android_webview/browser/gfx/parent_compositor_draw_constraints.cc b/android_webview/browser/gfx/parent_compositor_draw_constraints.cc index 2d6cd58f..7f49c8bb 100644 --- a/android_webview/browser/gfx/parent_compositor_draw_constraints.cc +++ b/android_webview/browser/gfx/parent_compositor_draw_constraints.cc
@@ -8,36 +8,22 @@ namespace android_webview { -ParentCompositorDrawConstraints::ParentCompositorDrawConstraints() - : is_layer(false), surface_rect_empty(true) {} +ParentCompositorDrawConstraints::ParentCompositorDrawConstraints() = default; ParentCompositorDrawConstraints::ParentCompositorDrawConstraints( - bool is_layer, - const gfx::Transform& transform, - bool surface_rect_empty) - : is_layer(is_layer), - transform(transform), - surface_rect_empty(surface_rect_empty) {} + const gfx::Size& viewport_size, + const gfx::Transform& transform) + : viewport_size(viewport_size), transform(transform) {} bool ParentCompositorDrawConstraints::NeedUpdate( const ChildFrame& frame) const { - if (is_layer != frame.is_layer || - transform != frame.transform_for_tile_priority) { - return true; - } - - // Viewport for tile priority does not depend on surface rect in this case. - if (frame.offscreen_pre_raster || is_layer) - return false; - - // Workaround for corner case. See crbug.com/417479. - return frame.viewport_rect_for_tile_priority_empty && !surface_rect_empty; + return viewport_size != frame.viewport_size_for_tile_priority || + transform != frame.transform_for_tile_priority; } bool ParentCompositorDrawConstraints::operator==( const ParentCompositorDrawConstraints& other) const { - return is_layer == other.is_layer && transform == other.transform && - surface_rect_empty == other.surface_rect_empty; + return viewport_size == other.viewport_size && transform == other.transform; } } // namespace android_webview
diff --git a/android_webview/browser/gfx/parent_compositor_draw_constraints.h b/android_webview/browser/gfx/parent_compositor_draw_constraints.h index c5bb094..16f5aa40 100644 --- a/android_webview/browser/gfx/parent_compositor_draw_constraints.h +++ b/android_webview/browser/gfx/parent_compositor_draw_constraints.h
@@ -5,6 +5,7 @@ #ifndef ANDROID_WEBVIEW_BROWSER_GFX_PARENT_COMPOSITOR_DRAW_CONSTRAINTS_H_ #define ANDROID_WEBVIEW_BROWSER_GFX_PARENT_COMPOSITOR_DRAW_CONSTRAINTS_H_ +#include "ui/gfx/geometry/size.h" #include "ui/gfx/transform.h" namespace android_webview { @@ -12,14 +13,12 @@ class ChildFrame; struct ParentCompositorDrawConstraints { - bool is_layer; + gfx::Size viewport_size; gfx::Transform transform; - bool surface_rect_empty; ParentCompositorDrawConstraints(); - ParentCompositorDrawConstraints(bool is_layer, - const gfx::Transform& transform, - bool surface_rect_empty); + ParentCompositorDrawConstraints(const gfx::Size& viewport_size, + const gfx::Transform& transform); bool NeedUpdate(const ChildFrame& frame) const; bool operator==(const ParentCompositorDrawConstraints& other) const;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java index 0779796..555513cb 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -6,9 +6,9 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.media.AudioManager; import android.net.Uri; -import android.os.Build; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; @@ -19,6 +19,7 @@ import android.webkit.URLUtil; import android.widget.FrameLayout; +import org.chromium.base.BuildInfo; import org.chromium.base.Callback; import org.chromium.base.ContentUriUtils; import org.chromium.base.ThreadUtils; @@ -158,8 +159,9 @@ // to be always run. boolean result = mContentsClient.onConsoleMessage( new AwConsoleMessage(message, sourceId, lineNumber, messageLevel)); - boolean isAppDebuggable = mContext.getApplicationInfo().FLAG_DEBUGGABLE != 0; - boolean isOsDebuggable = !Build.TYPE.equals("user"); + boolean isAppDebuggable = + (mContext.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + boolean isOsDebuggable = BuildInfo.isDebugAndroid(); // Always return true if not debuggable so js console messages won't be mirrored to logcat // for privacy. if (!isAppDebuggable && !isOsDebuggable) {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java index 04f3e4d..fbc58f46 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java
@@ -26,6 +26,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.JavaScriptUtils; +import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.util.TestWebServer; import java.util.ArrayList; @@ -102,8 +103,6 @@ String responseStr = "<html><head><title>TEST!</title></head><body>HELLO!</body></html>"; String url = webServer.setResponse(path, responseStr, null); - - url = webServer.setResponse(path, responseStr, null); mActivityTestRule.loadUrlSync( mAwContents, mContentsClient.getOnPageFinishedHelper(), url); final String jsCookieName = "js-test" + cookieSuffix; @@ -164,6 +163,42 @@ @Test @MediumTest + @Feature({"AndroidWebView", "Privacy"}) + public void testAcceptCookie_falseDoNotSendCookies() throws Throwable { + mCookieManager.setAcceptCookie(false); + AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents); + + EmbeddedTestServer embeddedTestServer = EmbeddedTestServer.createAndStartServer( + InstrumentationRegistry.getInstrumentation().getContext()); + try { + final String url = embeddedTestServer.getURL("/echoheader?Cookie"); + String cookieName = "java-test"; + mCookieManager.setCookie(url, cookieName + "=should-not-work"); + + String cookie = mCookieManager.getCookie(url); + Assert.assertNotNull( + "Setting cookies should still affect the CookieManager itself", cookie); + + mActivityTestRule.loadUrlSync( + mAwContents, mContentsClient.getOnPageFinishedHelper(), url); + String jsValue = getCookieWithJavaScript(cookieName); + String message = + "WebView should not expose cookies to JavaScript (with setAcceptCookie " + + "disabled)"; + Assert.assertEquals(message, "\"\"", jsValue); + + final String cookieHeader = mActivityTestRule.getJavaScriptResultBodyTextContent( + mAwContents, mContentsClient); + message = "WebView should not expose cookies via the Cookie header (with " + + "setAcceptCookie disabled)"; + Assert.assertEquals(message, "None", cookieHeader); + } finally { + embeddedTestServer.stopAndDestroyServer(); + } + } + + @Test + @MediumTest @Feature({"AndroidWebView"}) public void testEmbedderCanSeeRestrictedCookies() throws Throwable { TestWebServer webServer = TestWebServer.start(); @@ -198,6 +233,12 @@ + "; expires=' + expirationDate.toUTCString();"); } + private String getCookieWithJavaScript(final String name) throws Throwable { + return JSUtils.executeJavaScriptAndWaitForResult( + InstrumentationRegistry.getInstrumentation(), mAwContents, + mContentsClient.getOnEvaluateJavaScriptResultHelper(), "document.cookie"); + } + @Test @MediumTest @Feature({"AndroidWebView", "Privacy"}) @@ -877,13 +918,15 @@ private void validateCookies(String responseCookie, String... expectedCookieNames) { String[] cookies = responseCookie.split(";"); - Set<String> foundCookieNames = new HashSet<String>(); + // Convert to sets, since Set#equals() hooks in nicely with assertEquals() + Set<String> foundCookieNamesSet = new HashSet<String>(); for (String cookie : cookies) { - foundCookieNames.add(cookie.substring(0, cookie.indexOf("=")).trim()); + foundCookieNamesSet.add(cookie.substring(0, cookie.indexOf("=")).trim()); } - List<String> expectedCookieNamesList = Arrays.asList(expectedCookieNames); - Assert.assertEquals(expectedCookieNamesList.size(), foundCookieNames.size()); - Assert.assertTrue(foundCookieNames.containsAll(expectedCookieNamesList)); + Set<String> expectedCookieNamesSet = + new HashSet<String>(Arrays.asList(expectedCookieNames)); + Assert.assertEquals("Found cookies list differs from expected list", expectedCookieNamesSet, + foundCookieNamesSet); } private String makeExpiringCookie(String cookie, int secondsTillExpiry) {
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt index 4b79bfb0..057ae68 100644 --- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt +++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -107,6 +107,31 @@ getter onleavepictureinpicture setter onleavepictureinpicture +# Background Fetch API is not enabled in Android webview, crbug.com/766077 +interface BackgroundFetchManager + method fetch + method get + method getIds +interface BackgroundFetchRecord + getter request + getter responseReady +interface BackgroundFetchRegistration : EventTarget + getter downloadTotal + getter downloaded + getter failureReason + getter id + getter onprogress + getter recordsAvailable + getter result + getter uploadTotal + getter uploaded + method abort + method match + method matchAll + setter onprogress +interface ServiceWorkerRegistration : EventTarget + getter backgroundFetch + # support_webgl2_compute_context not supported on android, crbug.com/865569 interface WebGL2ComputeRenderingContext
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index f05c393..2e5ea4a 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -157,8 +157,6 @@ "app_list/app_list_controller_observer.h", "app_list/app_list_presenter_delegate_impl.cc", "app_list/app_list_presenter_delegate_impl.h", - "app_list/home_launcher_gesture_handler.cc", - "app_list/home_launcher_gesture_handler.h", "ash_export.h", "ash_service.cc", "assistant/assistant_alarm_timer_controller.cc", @@ -309,6 +307,12 @@ "highlighter/highlighter_result_view.h", "highlighter/highlighter_view.cc", "highlighter/highlighter_view.h", + "home_screen/home_launcher_gesture_handler.cc", + "home_screen/home_launcher_gesture_handler.h", + "home_screen/home_launcher_gesture_handler_observer.h", + "home_screen/home_screen_controller.cc", + "home_screen/home_screen_controller.h", + "home_screen/home_screen_delegate.h", "host/ash_window_tree_host.cc", "host/ash_window_tree_host.h", "host/ash_window_tree_host_init_params.h", @@ -1558,7 +1562,6 @@ "app_list/app_list_controller_impl_unittest.cc", "app_list/app_list_presenter_delegate_unittest.cc", "app_list/app_list_unittest.cc", - "app_list/home_launcher_gesture_handler_unittest.cc", "app_list/model/app_list_item_list_unittest.cc", "app_list/model/app_list_model_unittest.cc", "app_list/presenter/app_list_presenter_impl_unittest.cc", @@ -1616,6 +1619,7 @@ "frame/non_client_frame_view_ash_unittest.cc", "highlighter/highlighter_controller_unittest.cc", "highlighter/highlighter_gesture_util_unittest.cc", + "home_screen/home_launcher_gesture_handler_unittest.cc", "ime/ime_controller_unittest.cc", "ime/ime_focus_handler_unittest.cc", "keyboard/arc/arc_input_method_surface_manager_unittest.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index faf058c..307529d6e 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -9,7 +9,6 @@ #include "ash/app_list/app_list_controller_observer.h" #include "ash/app_list/app_list_presenter_delegate_impl.h" -#include "ash/app_list/home_launcher_gesture_handler.h" #include "ash/app_list/model/app_list_folder_item.h" #include "ash/app_list/model/app_list_item.h" #include "ash/app_list/model/app_list_view_state.h" @@ -23,6 +22,8 @@ #include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/assistant/util/assistant_util.h" #include "ash/assistant/util/deep_link_util.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/session/session_controller.h" @@ -94,9 +95,7 @@ AppListControllerImpl::AppListControllerImpl() : model_(std::make_unique<app_list::AppListModel>()), - presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)), - home_launcher_gesture_handler_( - std::make_unique<HomeLauncherGestureHandler>(this)) { + presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)) { model_->AddObserver(this); SessionController* session_controller = Shell::Get()->session_controller(); @@ -118,6 +117,8 @@ shell->mru_window_tracker()->AddObserver(this); if (app_list_features::IsEmbeddedAssistantUIEnabled()) shell->assistant_controller()->ui_controller()->AddModelObserver(this); + shell->home_screen_controller()->home_launcher_gesture_handler()->AddObserver( + this); } AppListControllerImpl::~AppListControllerImpl() = default; @@ -557,6 +558,9 @@ // Shell shutdown. void AppListControllerImpl::OnShellDestroying() { Shell* shell = Shell::Get(); + shell->home_screen_controller() + ->home_launcher_gesture_handler() + ->RemoveObserver(this); if (app_list_features::IsEmbeddedAssistantUIEnabled()) shell->assistant_controller()->ui_controller()->RemoveModelObserver(this); shell->mru_window_tracker()->RemoveObserver(this); @@ -692,9 +696,6 @@ // TODO(wutao): Handle tablet mode. switch (new_visibility) { case AssistantVisibility::kVisible: - if (!assistant::util::IsEmbeddedUiEntryPoint(entry_point.value())) - break; - if (IsTabletMode()) { MinimizeAllWindows(); } else if (!IsVisible()) { @@ -730,6 +731,26 @@ } } +void AppListControllerImpl::OnHomeLauncherAnimationComplete( + bool shown, + int64_t display_id) { + CloseAssistantUi(shown ? AssistantExitPoint::kLauncherOpen + : AssistantExitPoint::kLauncherClose); +} + +void AppListControllerImpl::UpdateYPositionAndOpacityForHomeLauncher( + int y_position_in_screen, + float opacity, + UpdateAnimationSettingsCallback callback) { + presenter_.UpdateYPositionAndOpacityForHomeLauncher( + y_position_in_screen, opacity, std::move(callback)); +} + +void AppListControllerImpl::UpdateAfterHomeLauncherShown() { + // Show or hide the expand arrow view. + UpdateExpandArrowVisibility(); +} + void AppListControllerImpl::Back() { presenter_.GetView()->Back(); } @@ -741,8 +762,12 @@ if (!IsTabletMode()) return ToggleAppList(display_id, show_source, event_time_stamp); - bool handled = home_launcher_gesture_handler_->ShowHomeLauncher( - Shell::Get()->display_manager()->GetDisplayForId(display_id)); + bool handled = + Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler() + ->ShowHomeLauncher( + Shell::Get()->display_manager()->GetDisplayForId(display_id)); if (!handled) { if (Shell::Get()->overview_controller()->IsSelecting()) { @@ -869,8 +894,15 @@ client_->OpenSearchResult(result_id, event_flags); } - if (IsTabletMode() && presenter_.IsVisible()) - presenter_.GetView()->CloseOpenedPage(); + ResetHomeLauncherIfShown(); +} + +void AppListControllerImpl::LogResultLaunchHistogram( + app_list::SearchResultLaunchLocation launch_location, + int suggestion_index) { + app_list::RecordSearchLaunchIndexAndQueryLength( + launch_location, static_cast<int>(last_raw_query_.size()), + suggestion_index); } void AppListControllerImpl::LogSearchClick( @@ -939,8 +971,7 @@ if (client_) client_->ActivateItem(id, event_flags); - if (IsTabletMode() && presenter_.IsVisible()) - presenter_.GetView()->CloseOpenedPage(); + ResetHomeLauncherIfShown(); } void AppListControllerImpl::GetContextMenuModel( @@ -966,16 +997,18 @@ bool AppListControllerImpl::ProcessHomeLauncherGesture( ui::GestureEvent* event, const gfx::Point& screen_location) { + HomeLauncherGestureHandler* home_launcher_gesture_handler = + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); switch (event->type()) { case ui::ET_SCROLL_FLING_START: case ui::ET_GESTURE_SCROLL_BEGIN: - return home_launcher_gesture_handler_->OnPressEvent( + return home_launcher_gesture_handler->OnPressEvent( HomeLauncherGestureHandler::Mode::kSlideDownToHide, screen_location); case ui::ET_GESTURE_SCROLL_UPDATE: - return home_launcher_gesture_handler_->OnScrollEvent( + return home_launcher_gesture_handler->OnScrollEvent( screen_location, event->details().scroll_y()); case ui::ET_GESTURE_END: - return home_launcher_gesture_handler_->OnReleaseEvent(screen_location); + return home_launcher_gesture_handler->OnReleaseEvent(screen_location); default: break; } @@ -993,8 +1026,10 @@ return false; } - return home_launcher_gesture_handler_ && - home_launcher_gesture_handler_->mode() != + HomeScreenController* home_screen_controller = + Shell::Get()->home_screen_controller(); + return home_screen_controller && + home_screen_controller->home_launcher_gesture_handler()->mode() != HomeLauncherGestureHandler::Mode::kSlideUpToShow; } @@ -1040,23 +1075,6 @@ client_->OnAppListTargetVisibilityChanged(visible); } -void AppListControllerImpl::NotifyHomeLauncherTargetPositionChanged( - bool showing, - int64_t display_id) { - for (auto& observer : observers_) - observer.OnHomeLauncherTargetPositionChanged(showing, display_id); -} - -void AppListControllerImpl::NotifyHomeLauncherAnimationComplete( - bool shown, - int64_t display_id) { - CloseAssistantUi(shown ? AssistantExitPoint::kLauncherOpen - : AssistantExitPoint::kLauncherClose); - - for (auto& observer : observers_) - observer.OnHomeLauncherAnimationComplete(shown, display_id); -} - //////////////////////////////////////////////////////////////////////////////// // Private used only: @@ -1157,4 +1175,17 @@ Shelf::ForWindow(presenter_.GetWindow())->MaybeUpdateShelfBackground(); } +void AppListControllerImpl::ResetHomeLauncherIfShown() { + if (!IsTabletMode() || !presenter_.IsVisible()) + return; + + auto* const keyboard_controller = keyboard::KeyboardController::Get(); + if (keyboard_controller->IsKeyboardVisible()) + keyboard_controller->HideKeyboardByUser(); + presenter_.GetView()->CloseOpenedPage(); + + // Refresh the suggestion chips with empty query. + StartSearch(base::string16()); +} + } // namespace ash
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h index 3a20e51..f1180ade 100644 --- a/ash/app_list/app_list_controller_impl.h +++ b/ash/app_list/app_list_controller_impl.h
@@ -19,6 +19,8 @@ #include "ash/ash_export.h" #include "ash/assistant/model/assistant_ui_model_observer.h" #include "ash/display/window_tree_host_manager.h" +#include "ash/home_screen/home_launcher_gesture_handler_observer.h" +#include "ash/home_screen/home_screen_delegate.h" #include "ash/public/cpp/assistant/default_voice_interaction_observer.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/interfaces/app_list.mojom.h" @@ -42,7 +44,6 @@ namespace ash { class AppListControllerObserver; -class HomeLauncherGestureHandler; // Ash's AppListController owns the AppListModel and implements interface // functions that allow Chrome to modify and observe the Shelf and AppListModel @@ -60,7 +61,9 @@ public DefaultVoiceInteractionObserver, public WindowTreeHostManager::Observer, public ash::MruWindowTracker::Observer, - public AssistantUiModelObserver { + public AssistantUiModelObserver, + public HomeLauncherGestureHandlerObserver, + public HomeScreenDelegate { public: using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr; using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr; @@ -147,9 +150,6 @@ app_list::AppListShowSource show_source, base::TimeTicks event_time_stamp); app_list::AppListViewState GetAppListViewState(); - HomeLauncherGestureHandler* home_launcher_gesture_handler() { - return home_launcher_gesture_handler_.get(); - } // Called when a window starts/ends dragging. If we're in tablet mode and home // launcher is enabled, we should hide the home launcher during dragging a @@ -166,6 +166,9 @@ void LogSearchClick(const std::string& result_id, int suggestion_index, ash::mojom::AppListLaunchedFrom launched_from) override; + void LogResultLaunchHistogram( + app_list::SearchResultLaunchLocation launch_location, + int suggestion_index) override; void InvokeSearchResultAction(const std::string& result_id, int action_index, int event_flags) override; @@ -206,11 +209,6 @@ void NotifyAppListVisibilityChanged(bool visible, int64_t display_id); void NotifyAppListTargetVisibilityChanged(bool visible); - // HomeLauncher visibility announcements are for tablet mode AppList. - void NotifyHomeLauncherTargetPositionChanged(bool showing, - int64_t display_id); - void NotifyHomeLauncherAnimationComplete(bool shown, int64_t display_id); - void FlushForTesting(); // ShellObserver: @@ -251,6 +249,16 @@ base::Optional<AssistantEntryPoint> entry_point, base::Optional<AssistantExitPoint> exit_point) override; + // HomeLauncherGestureHandlerObserver: + void OnHomeLauncherAnimationComplete(bool shown, int64_t display_id) override; + + // HomeScreenDelegate: + void UpdateYPositionAndOpacityForHomeLauncher( + int y_position_in_screen, + float opacity, + UpdateAnimationSettingsCallback callback) override; + void UpdateAfterHomeLauncherShown() override; + bool onscreen_keyboard_shown() const { return onscreen_keyboard_shown_; } // Performs the 'back' action for the active page. @@ -269,9 +277,6 @@ // Returns current visibility of the Assistant page. bool IsShowingEmbeddedAssistantUI() const; - // Updates the visibility of expand arrow view. - void UpdateExpandArrowVisibility(); - // Get updated app list view state after dragging from shelf. app_list::AppListViewState CalculateStateAfterShelfDrag( const ui::GestureEvent& gesture_in_screen, @@ -292,11 +297,16 @@ // Update the visibility of Assistant functionality. void UpdateAssistantVisibility(); + // Updates the visibility of expand arrow view. + void UpdateExpandArrowVisibility(); + int64_t GetDisplayIdToShowAppListOn(); // Shows the home launcher in tablet mode. void ShowHomeLauncher(); + void ResetHomeLauncherIfShown(); + base::string16 last_raw_query_; mojom::AppListClientPtr client_; @@ -311,10 +321,6 @@ // Bindings for the AppListController interface. mojo::BindingSet<mojom::AppListController> bindings_; - // Owned pointer to the object which handles gestures related to the home - // launcher. - std::unique_ptr<HomeLauncherGestureHandler> home_launcher_gesture_handler_; - // Whether the on-screen keyboard is shown. bool onscreen_keyboard_shown_ = false;
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc index 5f88541eb..4c62417 100644 --- a/ash/app_list/app_list_controller_impl_unittest.cc +++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -4,21 +4,30 @@ #include "ash/app_list/app_list_controller_impl.h" -#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/app_list/app_list_metrics.h" #include "ash/app_list/views/app_list_main_view.h" #include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/contents_view.h" #include "ash/app_list/views/expand_arrow_view.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" +#include "base/strings/string16.cc" +#include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" namespace ash { namespace { +using ::app_list::kAppListResultLaunchIndexAndQueryLength; +using ::app_list::kAppListTileLaunchIndexAndQueryLength; +using ::app_list::SearchResultLaunchLocation; + bool IsTabletMode() { return Shell::Get() ->tablet_mode_controller() @@ -68,7 +77,7 @@ // because w1 still exists. wm::ActivateWindow(w1.get()); Shell::Get() - ->app_list_controller() + ->home_screen_controller() ->home_launcher_gesture_handler() ->ShowHomeLauncher(display::Screen::GetScreen()->GetPrimaryDisplay()); EXPECT_EQ(mojom::WindowStateType::MINIMIZED, @@ -85,4 +94,74 @@ EXPECT_FALSE(GetExpandArrowViewVisibility()); } +class AppListControllerImplMetricsTest : public AshTestBase { + public: + AppListControllerImplMetricsTest() = default; + ~AppListControllerImplMetricsTest() override = default; + + void SetUp() override { + AshTestBase::SetUp(); + controller_ = ash::Shell::Get()->app_list_controller(); + } + + AppListControllerImpl* controller_; + const base::HistogramTester histogram_tester_; + + private: + DISALLOW_COPY_AND_ASSIGN(AppListControllerImplMetricsTest); +}; + +TEST_F(AppListControllerImplMetricsTest, LogSingleResultListClick) { + histogram_tester_.ExpectTotalCount(kAppListResultLaunchIndexAndQueryLength, + 0); + controller_->StartSearch(base::string16()); + controller_->LogResultLaunchHistogram(SearchResultLaunchLocation::kResultList, + 4); + histogram_tester_.ExpectUniqueSample(kAppListResultLaunchIndexAndQueryLength, + 4, 1); +} + +TEST_F(AppListControllerImplMetricsTest, LogSingleTileListClick) { + histogram_tester_.ExpectTotalCount(kAppListTileLaunchIndexAndQueryLength, 0); + controller_->StartSearch(base::ASCIIToUTF16("aaaa")); + controller_->LogResultLaunchHistogram(SearchResultLaunchLocation::kTileList, + 4); + histogram_tester_.ExpectUniqueSample(kAppListTileLaunchIndexAndQueryLength, + 32, 1); +} + +TEST_F(AppListControllerImplMetricsTest, LogOneClickInEveryBucket) { + histogram_tester_.ExpectTotalCount(kAppListResultLaunchIndexAndQueryLength, + 0); + for (int query_length = 0; query_length < 11; ++query_length) { + const base::string16 query = + base::ASCIIToUTF16(std::string(query_length, 'a')); + for (int click_index = 0; click_index < 7; ++click_index) { + controller_->StartSearch(query); + controller_->LogResultLaunchHistogram( + SearchResultLaunchLocation::kResultList, click_index); + } + } + + histogram_tester_.ExpectTotalCount(kAppListResultLaunchIndexAndQueryLength, + 77); + for (int query_length = 0; query_length < 11; ++query_length) { + for (int click_index = 0; click_index < 7; ++click_index) { + histogram_tester_.ExpectBucketCount( + kAppListResultLaunchIndexAndQueryLength, + 7 * query_length + click_index, 1); + } + } +} + +TEST_F(AppListControllerImplMetricsTest, LogManyClicksInOneBucket) { + histogram_tester_.ExpectTotalCount(kAppListTileLaunchIndexAndQueryLength, 0); + controller_->StartSearch(base::ASCIIToUTF16("aaaa")); + for (int i = 0; i < 50; ++i) + controller_->LogResultLaunchHistogram(SearchResultLaunchLocation::kTileList, + 4); + histogram_tester_.ExpectUniqueSample(kAppListTileLaunchIndexAndQueryLength, + 32, 50); +} + } // namespace ash
diff --git a/ash/app_list/app_list_controller_observer.h b/ash/app_list/app_list_controller_observer.h index 227d384..920e69b 100644 --- a/ash/app_list/app_list_controller_observer.h +++ b/ash/app_list/app_list_controller_observer.h
@@ -14,13 +14,6 @@ public: // Called when the AppList is shown or dismissed. virtual void OnAppListVisibilityChanged(bool shown, int64_t display_id) {} - // Called when the HomeLauncher has started to be dragged, or a positional - // animation has begin. - virtual void OnHomeLauncherTargetPositionChanged(bool showing, - int64_t display_id) {} - // Called when the HomeLauncher positional animation has completed. - virtual void OnHomeLauncherAnimationComplete(bool shown, int64_t display_id) { - } }; } // namespace ash
diff --git a/ash/app_list/app_list_metrics.cc b/ash/app_list/app_list_metrics.cc index e4f9ff1..57a1e07 100644 --- a/ash/app_list/app_list_metrics.cc +++ b/ash/app_list/app_list_metrics.cc
@@ -4,6 +4,8 @@ #include "ash/app_list/app_list_metrics.h" +#include <algorithm> + #include "ash/app_list/model/app_list_model.h" #include "ash/app_list/model/search/search_model.h" #include "ash/app_list/model/search/search_result.h" @@ -27,6 +29,16 @@ return smoothness; } +// These constants affect logging, and should not be changed without +// deprecating the following UMA histograms: +// - Apps.AppListTileClickIndexAndQueryLength +// - Apps.AppListResultClickIndexAndQueryLength +constexpr int kMaxLoggedQueryLength = 10; +constexpr int kMaxLoggedSuggestionIndex = 6; +constexpr int kMaxLoggedHistogramValue = + (kMaxLoggedSuggestionIndex + 1) * kMaxLoggedQueryLength + + kMaxLoggedSuggestionIndex; + } // namespace // The UMA histogram that logs smoothness of folder show/hide animation. @@ -100,6 +112,29 @@ ApplistSearchResultOpenedSource::kMaxApplistSearchResultOpenedSource); } +void RecordSearchLaunchIndexAndQueryLength( + SearchResultLaunchLocation launch_location, + int query_length, + int suggestion_index) { + if (suggestion_index < 0) { + LOG(ERROR) << "Received invalid suggestion index."; + return; + } + + query_length = std::min(query_length, kMaxLoggedQueryLength); + suggestion_index = std::min(suggestion_index, kMaxLoggedSuggestionIndex); + const int logged_value = + (kMaxLoggedSuggestionIndex + 1) * query_length + suggestion_index; + + if (launch_location == SearchResultLaunchLocation::kResultList) { + UMA_HISTOGRAM_EXACT_LINEAR(kAppListResultLaunchIndexAndQueryLength, + logged_value, kMaxLoggedHistogramValue); + } else if (launch_location == SearchResultLaunchLocation::kTileList) { + UMA_HISTOGRAM_EXACT_LINEAR(kAppListTileLaunchIndexAndQueryLength, + logged_value, kMaxLoggedHistogramValue); + } +} + void RecordZeroStateSearchResultUserActionHistogram( ZeroStateSearchResultUserActionType action) { UMA_HISTOGRAM_ENUMERATION(kAppListZeroStateSearchResultUserActionHistogram,
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h index 29e1dce5..6bb5ad9e7 100644 --- a/ash/app_list/app_list_metrics.h +++ b/ash/app_list/app_list_metrics.h
@@ -59,6 +59,16 @@ // The UMA histogram that logs how the app list is shown. constexpr char kAppListToggleMethodHistogram[] = "Apps.AppListShowSource"; +// The UMA histogram that logs the index launched item in the results list and +// the query length. +constexpr char kAppListResultLaunchIndexAndQueryLength[] = + "Apps.AppListResultLaunchIndexAndQueryLength"; + +// The UMA histogram that logs the index launched item in the app tile list and +// the query length. +constexpr char kAppListTileLaunchIndexAndQueryLength[] = + "Apps.AppListTileLaunchIndexAndQueryLength"; + // The UMA histogram that logs which page gets opened by the user. constexpr char kPageOpenedHistogram[] = "Apps.AppListPageOpened"; @@ -189,6 +199,14 @@ kMaxAppListAppMovingType = 5, }; +// Different places a search result can be launched from. These values do not +// persist to logs, so can be changed as-needed. However, changes should be +// reflected in RecordSearchLaunchIndexAndQueryLength(). +enum SearchResultLaunchLocation { + kResultList = 0, + kTileList = 1, +}; + void RecordFolderShowHideAnimationSmoothness(int actual_frames, int ideal_duration_ms, float refresh_rate); @@ -208,6 +226,11 @@ const AppListModel* model, const SearchModel* search_model); +APP_LIST_EXPORT void RecordSearchLaunchIndexAndQueryLength( + SearchResultLaunchLocation launch_location, + int query_length, + int suggestion_index); + } // namespace app_list #endif // ASH_APP_LIST_APP_LIST_METRICS_H_
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h index afb1107..7312d46 100644 --- a/ash/app_list/app_list_view_delegate.h +++ b/ash/app_list/app_list_view_delegate.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "ash/app_list/app_list_metrics.h" #include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/public/cpp/ash_public_export.h" #include "ash/public/interfaces/app_list.mojom.h" @@ -60,6 +61,16 @@ int suggestion_index, ash::mojom::AppListLaunchedFrom launched_from) = 0; + // Called to log UMA metrics for the launch of an item either in the app tile + // list or the search result list. The |launch_location| argument determines + // which histogram to log to. |suggestion_index| represents the index of the + // launched item in its list view, not the overall position in the suggestion + // window. For instance, the first launcher result item is index 0, regardless + // of if there is an answer card above it. + virtual void LogResultLaunchHistogram( + app_list::SearchResultLaunchLocation launch_location, + int suggestion_index) = 0; + // Called to invoke a custom action on a result with |result_id|. // |action_index| corresponds to the index of an icon in // |result.action_icons()|.
diff --git a/ash/app_list/test/app_list_test_view_delegate.h b/ash/app_list/test/app_list_test_view_delegate.h index 36b1897d..8b1885cb 100644 --- a/ash/app_list/test/app_list_test_view_delegate.h +++ b/ash/app_list/test/app_list_test_view_delegate.h
@@ -63,6 +63,9 @@ void LogSearchClick(const std::string& result_id, int suggestion_index, ash::mojom::AppListLaunchedFrom launched_from) override {} + void LogResultLaunchHistogram( + app_list::SearchResultLaunchLocation launch_location, + int suggestion_index) override {} void InvokeSearchResultAction(const std::string& result_id, int action_index, int event_flags) override {}
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc index 4e42f02c..dbd85ba 100644 --- a/ash/app_list/views/assistant/assistant_page_view.cc +++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -10,6 +10,12 @@ #include "ash/app_list/app_list_view_delegate.h" #include "ash/app_list/views/assistant/assistant_main_view.h" #include "ash/app_list/views/contents_view.h" +#include "ash/assistant/model/assistant_ui_model.h" +#include "ash/assistant/ui/assistant_view_delegate.h" +#include "ash/assistant/util/assistant_util.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/search_box/search_box_constants.h" #include "ui/views/background.h" #include "ui/views/focus/focus_manager.h" @@ -32,9 +38,16 @@ ash::AssistantViewDelegate* assistant_view_delegate) : assistant_view_delegate_(assistant_view_delegate) { InitLayout(); + + // |assistant_view_delegate_| could be nullptr in test. + if (assistant_view_delegate_) + assistant_view_delegate_->AddUiModelObserver(this); } -AssistantPageView::~AssistantPageView() = default; +AssistantPageView::~AssistantPageView() { + if (assistant_view_delegate_) + assistant_view_delegate_->RemoveUiModelObserver(this); +} void AssistantPageView::InitLayout() { SetPaintToLayer(); @@ -50,7 +63,6 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); - // |assistant_view_delegate_| could be nullptr in test. if (assistant_view_delegate_) { assistant_main_view_ = new AssistantMainView(assistant_view_delegate_); AddChildView(assistant_main_view_); @@ -75,6 +87,11 @@ mask_->layer()->SetBounds(GetLocalBounds()); } +void AssistantPageView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + View::GetAccessibleNodeData(node_data); + node_data->SetName(l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_WINDOW)); +} + void AssistantPageView::OnMouseEvent(ui::MouseEvent* event) { switch (event->type()) { case ui::ET_MOUSE_PRESSED: @@ -137,4 +154,23 @@ this, GetWidget(), /*reverse=*/true, /*dont_loop=*/false); } +void AssistantPageView::OnUiVisibilityChanged( + ash::AssistantVisibility new_visibility, + ash::AssistantVisibility old_visibility, + base::Optional<ash::AssistantEntryPoint> entry_point, + base::Optional<ash::AssistantExitPoint> exit_point) { + if (!assistant_view_delegate_) + return; + + if (new_visibility != ash::AssistantVisibility::kVisible) + return; + + const bool prefer_voice = assistant_view_delegate_->IsTabletMode() || + assistant_view_delegate_->IsLaunchWithMicOpen(); + if (!ash::assistant::util::IsVoiceEntryPoint(entry_point.value(), + prefer_voice)) { + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); + } +} + } // namespace app_list
diff --git a/ash/app_list/views/assistant/assistant_page_view.h b/ash/app_list/views/assistant/assistant_page_view.h index 844800c..399a9e1 100644 --- a/ash/app_list/views/assistant/assistant_page_view.h +++ b/ash/app_list/views/assistant/assistant_page_view.h
@@ -7,8 +7,10 @@ #include "ash/app_list/app_list_export.h" #include "ash/app_list/views/app_list_page.h" +#include "ash/assistant/model/assistant_ui_model_observer.h" #include "ash/public/cpp/app_list/app_list_types.h" #include "base/macros.h" +#include "base/optional.h" namespace ash { class AssistantViewDelegate; @@ -23,7 +25,8 @@ class AssistantMainView; // The Assistant page for the app list. -class APP_LIST_EXPORT AssistantPageView : public AppListPage { +class APP_LIST_EXPORT AssistantPageView : public AppListPage, + public ash::AssistantUiModelObserver { public: explicit AssistantPageView( ash::AssistantViewDelegate* assistant_view_delegate); @@ -37,6 +40,7 @@ gfx::Size CalculatePreferredSize() const override; void RequestFocus() override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; // ui::EventHandler: void OnMouseEvent(ui::MouseEvent* event) override; @@ -48,6 +52,13 @@ views::View* GetFirstFocusableView() override; views::View* GetLastFocusableView() override; + // AssistantUiModelObserver: + void OnUiVisibilityChanged( + ash::AssistantVisibility new_visibility, + ash::AssistantVisibility old_visibility, + base::Optional<ash::AssistantEntryPoint> entry_point, + base::Optional<ash::AssistantExitPoint> exit_point) override; + private: ash::AssistantViewDelegate* const assistant_view_delegate_;
diff --git a/ash/app_list/views/assistant/dialog_plate.cc b/ash/app_list/views/assistant/dialog_plate.cc index 6b6571a..2fea69f 100644 --- a/ash/app_list/views/assistant/dialog_plate.cc +++ b/ash/app_list/views/assistant/dialog_plate.cc
@@ -415,17 +415,9 @@ textfield_->RequestFocus(); break; case ash::InputModality::kVoice: + animated_voice_input_toggle_->RequestFocus(); + break; case ash::InputModality::kStylus: - // When not using |kKeyboard| input modality we need to explicitly clear - // focus if the focused view is |textfield_| or |voice_input_toggle_| to - // prevent it from being read by ChromeVox. Clearing focus also allows - // AssistantContainerView's focus traversal to be reset. - views::FocusManager* focus_manager = GetFocusManager(); - if (focus_manager && - (focus_manager->GetFocusedView() == textfield_ || - focus_manager->GetFocusedView() == voice_input_toggle_)) { - focus_manager->ClearFocus(); - } break; } }
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc index 32c7f4b4..d432f1e 100644 --- a/ash/app_list/views/contents_view.cc +++ b/ash/app_list/views/contents_view.cc
@@ -485,6 +485,7 @@ keyboard_controller->HideKeyboardByUser(); return true; } + ash::AppListState state = view_to_state_[GetActivePageIndex()]; switch (state) { case ash::AppListState::kStateStart:
diff --git a/ash/app_list/views/search_result_list_view.cc b/ash/app_list/views/search_result_list_view.cc index 787d0e8..c14ef523 100644 --- a/ash/app_list/views/search_result_list_view.cc +++ b/ash/app_list/views/search_result_list_view.cc
@@ -43,6 +43,7 @@ for (int i = 0; i < kMaxResults; ++i) { search_result_views_.emplace_back( new SearchResultView(this, view_delegate_)); + search_result_views_.back()->set_index_in_search_result_list_view(i); results_container_->AddChildView(search_result_views_.back()); AddObservedResultView(search_result_views_.back()); } @@ -124,6 +125,9 @@ if (view_delegate_ && view->result()) { RecordSearchResultOpenSource(view->result(), view_delegate_->GetModel(), view_delegate_->GetSearchModel()); + view_delegate_->LogResultLaunchHistogram( + SearchResultLaunchLocation::kResultList, + view->get_index_in_search_result_list_view()); view_delegate_->OpenSearchResult(view->result()->id(), event_flags); } }
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc index a4e6ed0..ecb334c 100644 --- a/ash/app_list/views/search_result_tile_item_view.cc +++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -257,6 +257,8 @@ RecordSearchResultOpenSource(result(), view_delegate_->GetModel(), view_delegate_->GetSearchModel()); view_delegate_->OpenSearchResult(result()->id(), event.flags()); + view_delegate_->LogResultLaunchHistogram( + SearchResultLaunchLocation::kTileList, index_in_item_list_view_); view_delegate_->LogSearchClick( result()->id(), index_in_item_list_view_, ash::mojom::AppListLaunchedFrom::kLaunchedFromSearchBox);
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h index cec2ae5..79130484 100644 --- a/ash/app_list/views/search_result_view.h +++ b/ash/app_list/views/search_result_view.h
@@ -64,6 +64,16 @@ // Computes the button's spoken feedback name. base::string16 ComputeAccessibleName() const; + // Gets the index of this result in the |SearchResultListView|. + int get_index_in_search_result_list_view() const { + return index_in_search_result_list_view_; + } + + // Stores the index of this result in the |SearchResultListView|. + void set_index_in_search_result_list_view(size_t index) { + index_in_search_result_list_view_ = index; + } + void set_is_last_result(bool is_last) { is_last_result_ = is_last; } // AppListMenuModelAdapter::Delegate overrides: @@ -151,6 +161,10 @@ // Whether the removal confirmation dialog is invoked by long press touch. bool confirm_remove_by_long_press_ = false; + // The index of this item in the search_result_tile_item_list_view, only + // used for logging. + int index_in_search_result_list_view_ = -1; + base::WeakPtrFactory<SearchResultView> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(SearchResultView);
diff --git a/ash/ash_service_unittest.cc b/ash/ash_service_unittest.cc index 9bd86bd..62a9fcac9 100644 --- a/ash/ash_service_unittest.cc +++ b/ash/ash_service_unittest.cc
@@ -91,19 +91,20 @@ // service_manager::test::ServiceTest: void SetUp() override { - aura::test::EnvTestHelper().SetMode(aura::Env::Mode::MUS); + old_mode_ = aura::test::EnvTestHelper().SetMode(aura::Env::Mode::MUS); } void TearDown() override { // Unset the screen installed by the test. display::Screen::SetScreenInstance(nullptr); - aura::test::EnvTestHelper().SetMode(aura::Env::Mode::LOCAL); + aura::test::EnvTestHelper().SetMode(old_mode_); } protected: service_manager::Connector* connector() { return test_service_.connector(); } private: + aura::Env::Mode old_mode_ = aura::Env::Mode::LOCAL; base::test::ScopedTaskEnvironment task_environment_; service_manager::TestServiceManager test_service_manager_; service_manager::TestService test_service_;
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc index d4d8e2e..b3e746c5 100644 --- a/ash/assistant/assistant_interaction_controller.cc +++ b/ash/assistant/assistant_interaction_controller.cc
@@ -16,8 +16,10 @@ #include "ash/assistant/model/assistant_ui_element.h" #include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" +#include "ash/assistant/util/assistant_util.h" #include "ash/assistant/util/deep_link_util.h" #include "ash/assistant/util/histogram_util.h" +#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/ash_pref_names.h" #include "ash/public/interfaces/voice_interaction_controller.mojom.h" #include "ash/session/session_controller.h" @@ -209,10 +211,13 @@ HighlighterEnabledState state) { switch (state) { case HighlighterEnabledState::kEnabled: - model_.SetInputModality(InputModality::kStylus); + // Skip setting input modality to stylus when the embedded Assistant + // feature is enabled to prevent highlighter aborting sessions in + // OnUiModeChanged. + if (!app_list_features::IsEmbeddedAssistantUIEnabled()) + model_.SetInputModality(InputModality::kStylus); break; case HighlighterEnabledState::kDisabledByUser: - FALLTHROUGH; case HighlighterEnabledState::kDisabledBySessionComplete: model_.SetInputModality(InputModality::kKeyboard); break; @@ -227,6 +232,7 @@ void AssistantInteractionController::OnHighlighterSelectionRecognized( const gfx::Rect& rect) { + assistant_controller_->ui_controller()->ShowUi(AssistantEntryPoint::kStylus); StartMetalayerInteraction(/*region=*/rect); } @@ -620,38 +626,36 @@ DCHECK_EQ(AssistantVisibility::kVisible, assistant_controller_->ui_controller()->model()->visibility()); - bool launch_with_mic_open = + const bool launch_with_mic_open = Shell::Get()->voice_interaction_controller()->launch_with_mic_open(); + const bool prefer_voice = launch_with_mic_open || IsTabletMode(); - switch (entry_point) { - case AssistantEntryPoint::kLauncherSearchBoxMic: - launch_with_mic_open = true; - FALLTHROUGH; - case AssistantEntryPoint::kHotkey: - case AssistantEntryPoint::kLauncherSearchBox: - case AssistantEntryPoint::kLongPressLauncher: { - // When the user prefers it or when we are in tablet mode, launching - // Assistant UI will immediately start a voice interaction. - if (launch_with_mic_open || IsTabletMode()) { - StartVoiceInteraction(); - should_attempt_warmer_welcome_ = false; - } - break; - } - case AssistantEntryPoint::kStylus: - model_.SetInputModality(InputModality::kStylus); - FALLTHROUGH; - case AssistantEntryPoint::kDeepLink: - case AssistantEntryPoint::kHotword: - case AssistantEntryPoint::kLauncherSearchResult: - should_attempt_warmer_welcome_ = false; - break; - case AssistantEntryPoint::kUnspecified: - case AssistantEntryPoint::kSetup: - // No action necessary. - break; + // We don't explicitly start a new voice interaction if the entry point + // is hotword since in such cases a voice interaction will already be in + // progress. + if (assistant::util::IsVoiceEntryPoint(entry_point, prefer_voice) && + entry_point != AssistantEntryPoint::kHotword) { + should_attempt_warmer_welcome_ = false; + StartVoiceInteraction(); + return; } + if (entry_point == AssistantEntryPoint::kStylus) { + should_attempt_warmer_welcome_ = false; + // When the embedded Assistant feature is enabled, we call ShowUi(kStylus) + // OnHighlighterSelectionRecognized. But we are not actually using stylus. + if (!app_list_features::IsEmbeddedAssistantUIEnabled()) + model_.SetInputModality(InputModality::kStylus); + return; + } + + if (!chromeos::assistant::features::IsWarmerWelcomeEnabled()) + return; + + should_attempt_warmer_welcome_ = + should_attempt_warmer_welcome_ && + assistant::util::ShouldAttemptWarmerWelcome(entry_point); + // Explicitly check the interaction state to ensure warmer welcome will // not interrupt any ongoing active interactions. This happens, for example, // when the first Assistant launch of the current user session is trigger by @@ -660,31 +664,30 @@ if (model_.interaction_state() == InteractionState::kActive) should_attempt_warmer_welcome_ = false; + if (!should_attempt_warmer_welcome_) + return; + // TODO(yileili): Currently WW is only triggered when the first Assistant // launch of the user session does not automatically start an interaction that // would otherwise cause us to interrupt the user. Need further UX design to // attempt WW after the first interaction. - if (should_attempt_warmer_welcome_) { - if (chromeos::assistant::features::IsWarmerWelcomeEnabled()) { - auto* pref_service = - Shell::Get()->session_controller()->GetLastActiveUserPrefService(); + auto* pref_service = + Shell::Get()->session_controller()->GetLastActiveUserPrefService(); - DCHECK(pref_service); + DCHECK(pref_service); - auto num_warmer_welcome_triggered = - pref_service->GetInteger(prefs::kAssistantNumWarmerWelcomeTriggered); - if (num_warmer_welcome_triggered < kWarmerWelcomesMaxTimesTriggered) { - // If the user has opted to launch Assistant with the mic open, we can - // reasonably assume there is an expectation of TTS. - assistant_->StartWarmerWelcomeInteraction( - num_warmer_welcome_triggered, - /*allow_tts=*/launch_with_mic_open); - pref_service->SetInteger(prefs::kAssistantNumWarmerWelcomeTriggered, - ++num_warmer_welcome_triggered); - } - } - should_attempt_warmer_welcome_ = false; + auto num_warmer_welcome_triggered = + pref_service->GetInteger(prefs::kAssistantNumWarmerWelcomeTriggered); + if (num_warmer_welcome_triggered < kWarmerWelcomesMaxTimesTriggered) { + // If the user has opted to launch Assistant with the mic open, we can + // reasonably assume there is an expectation of TTS. + assistant_->StartWarmerWelcomeInteraction( + num_warmer_welcome_triggered, + /*allow_tts=*/launch_with_mic_open); + pref_service->SetInteger(prefs::kAssistantNumWarmerWelcomeTriggered, + ++num_warmer_welcome_triggered); } + should_attempt_warmer_welcome_ = false; } void AssistantInteractionController::StartMetalayerInteraction(
diff --git a/ash/assistant/assistant_ui_controller.cc b/ash/assistant/assistant_ui_controller.cc index d601a62..5ded0031 100644 --- a/ash/assistant/assistant_ui_controller.cc +++ b/ash/assistant/assistant_ui_controller.cc
@@ -35,6 +35,8 @@ // Toast ----------------------------------------------------------------------- constexpr int kToastDurationMs = 2500; + +constexpr char kStylusPromptToastId[] = "stylus_prompt_for_embedded_ui"; constexpr char kUnboundServiceToastId[] = "assistant_controller_unbound_service"; @@ -188,9 +190,13 @@ void AssistantUiController::OnHighlighterEnabledChanged( HighlighterEnabledState state) { - // TODO(wutao): Behavior is not defined. - if (model_.ui_mode() == AssistantUiMode::kLauncherEmbeddedUi) + if (app_list_features::IsEmbeddedAssistantUIEnabled()) { + if (state == HighlighterEnabledState::kEnabled) { + ShowToast(kStylusPromptToastId, IDS_ASH_ASSISTANT_PROMPT_STYLUS); + CloseUi(AssistantExitPoint::kStylus); + } return; + } switch (state) { case HighlighterEnabledState::kEnabled: @@ -328,10 +334,11 @@ // Metalayer should not be sticky. Disable when the UI is no longer visible. if (old_visibility == AssistantVisibility::kVisible) { - Shell::Get()->highlighter_controller()->AbortSession(); + if (exit_point != AssistantExitPoint::kStylus) + Shell::Get()->highlighter_controller()->AbortSession(); // Only record the exit point when Assistant UI becomes invisible to - // avoid duplicate happens (e.g., pressing ESC key). + // avoid recording duplicate events (e.g. pressing ESC key). assistant::util::RecordAssistantExitPoint(exit_point.value()); } } @@ -356,11 +363,7 @@ return; } - if (app_list_features::IsEmbeddedAssistantUIEnabled() && - assistant::util::IsEmbeddedUiEntryPoint(entry_point)) { - // No container view when embedded in launcher. - DCHECK(!container_view_); - + if (app_list_features::IsEmbeddedAssistantUIEnabled()) { model_.SetUiMode(AssistantUiMode::kLauncherEmbeddedUi); model_.SetVisible(entry_point); return; @@ -445,9 +448,10 @@ return; } - // TODO(wutao): Behavior is not defined. - if (model_.ui_mode() == AssistantUiMode::kLauncherEmbeddedUi) + if (app_list_features::IsEmbeddedAssistantUIEnabled()) { + model_.SetUiMode(AssistantUiMode::kLauncherEmbeddedUi); return; + } InputModality input_modality = assistant_controller_->interaction_controller() ->model() @@ -567,6 +571,9 @@ } void AssistantUiController::CreateContainerView() { + DCHECK(!container_view_); + DCHECK(!app_list_features::IsEmbeddedAssistantUIEnabled()); + container_view_ = new AssistantContainerView(assistant_controller_->view_delegate()); container_view_->GetWidget()->AddObserver(this);
diff --git a/ash/assistant/assistant_view_delegate_impl.cc b/ash/assistant/assistant_view_delegate_impl.cc index cc263c9..de9f901 100644 --- a/ash/assistant/assistant_view_delegate_impl.cc +++ b/ash/assistant/assistant_view_delegate_impl.cc
@@ -131,6 +131,10 @@ return Shell::Get()->GetRootWindowForNewWindows(); } +bool AssistantViewDelegateImpl::IsLaunchWithMicOpen() const { + return Shell::Get()->voice_interaction_controller()->launch_with_mic_open(); +} + bool AssistantViewDelegateImpl::IsTabletMode() const { return Shell::Get() ->tablet_mode_controller()
diff --git a/ash/assistant/assistant_view_delegate_impl.h b/ash/assistant/assistant_view_delegate_impl.h index ca21607..6bd6096 100644 --- a/ash/assistant/assistant_view_delegate_impl.h +++ b/ash/assistant/assistant_view_delegate_impl.h
@@ -54,6 +54,7 @@ void GetNavigableContentsFactoryForView( content::mojom::NavigableContentsFactoryRequest request) override; aura::Window* GetRootWindowForNewWindows() override; + bool IsLaunchWithMicOpen() const override; bool IsTabletMode() const override; void OnDialogPlateButtonPressed(AssistantButtonId id) override; void OnDialogPlateContentsCommitted(const std::string& text) override;
diff --git a/ash/assistant/ui/assistant_view_delegate.h b/ash/assistant/ui/assistant_view_delegate.h index 540d79a..d4382013 100644 --- a/ash/assistant/ui/assistant_view_delegate.h +++ b/ash/assistant/ui/assistant_view_delegate.h
@@ -142,6 +142,9 @@ // Returns the root window that newly created windows should be added to. virtual aura::Window* GetRootWindowForNewWindows() = 0; + // Returns true if user prefers to start with voice interaction. + virtual bool IsLaunchWithMicOpen() const = 0; + // Returns true if in tablet mode. virtual bool IsTabletMode() const = 0;
diff --git a/ash/assistant/util/assistant_util.cc b/ash/assistant/util/assistant_util.cc index 280e954..16f9cc8 100644 --- a/ash/assistant/util/assistant_util.cc +++ b/ash/assistant/util/assistant_util.cc
@@ -20,15 +20,39 @@ return new_visibility == AssistantVisibility::kClosed; } -bool IsEmbeddedUiEntryPoint(AssistantEntryPoint entry_point) { - return entry_point == AssistantEntryPoint::kDeepLink || - entry_point == AssistantEntryPoint::kHotkey || - entry_point == AssistantEntryPoint::kHotword || - entry_point == AssistantEntryPoint::kLauncherSearchBox || - entry_point == AssistantEntryPoint::kLauncherSearchBoxMic || - entry_point == AssistantEntryPoint::kLauncherSearchResult || - entry_point == AssistantEntryPoint::kLongPressLauncher || - entry_point == AssistantEntryPoint::kUnspecified; +bool IsVoiceEntryPoint(AssistantEntryPoint entry_point, bool prefer_voice) { + switch (entry_point) { + case AssistantEntryPoint::kHotword: + case AssistantEntryPoint::kLauncherSearchBoxMic: + return true; + case AssistantEntryPoint::kHotkey: + case AssistantEntryPoint::kLauncherSearchBox: + case AssistantEntryPoint::kLongPressLauncher: + return prefer_voice; + case AssistantEntryPoint::kUnspecified: + case AssistantEntryPoint::kDeepLink: + case AssistantEntryPoint::kLauncherSearchResult: + case AssistantEntryPoint::kSetup: + case AssistantEntryPoint::kStylus: + return false; + } +} + +bool ShouldAttemptWarmerWelcome(AssistantEntryPoint entry_point) { + switch (entry_point) { + case AssistantEntryPoint::kDeepLink: + case AssistantEntryPoint::kHotword: + case AssistantEntryPoint::kLauncherSearchBoxMic: + case AssistantEntryPoint::kLauncherSearchResult: + case AssistantEntryPoint::kStylus: + return false; + case AssistantEntryPoint::kUnspecified: + case AssistantEntryPoint::kHotkey: + case AssistantEntryPoint::kLauncherSearchBox: + case AssistantEntryPoint::kLongPressLauncher: + case AssistantEntryPoint::kSetup: + return true; + } } } // namespace util
diff --git a/ash/assistant/util/assistant_util.h b/ash/assistant/util/assistant_util.h index 0c239595..720b20871 100644 --- a/ash/assistant/util/assistant_util.h +++ b/ash/assistant/util/assistant_util.h
@@ -24,10 +24,16 @@ COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsFinishingSession(AssistantVisibility new_visibility); -// Returns true if the |entry_point| should show the embedded Assistant UI in -// Launcher. +// Returns true if the |entry_point| should start Assistant with a voice +// interaction. +// |prefer_voice| is true if user prefers voice input modality or if the device +// is in tablet mode. COMPONENT_EXPORT(ASSISTANT_UTIL) -bool IsEmbeddedUiEntryPoint(AssistantEntryPoint entry_point); +bool IsVoiceEntryPoint(AssistantEntryPoint entry_point, bool prefer_voice); + +// Returns true if the |entry_point| should attempt warmer welcome. +COMPONENT_EXPORT(ASSISTANT_UTIL) +bool ShouldAttemptWarmerWelcome(AssistantEntryPoint entry_point); } // namespace util } // namespace assistant
diff --git a/ash/autoclick/autoclick_unittest.cc b/ash/autoclick/autoclick_unittest.cc index 900d90e..96c61d3 100644 --- a/ash/autoclick/autoclick_unittest.cc +++ b/ash/autoclick/autoclick_unittest.cc
@@ -515,8 +515,7 @@ EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags()); } -// TODO(crbug.com/935651): The test has flaky crashes. -TEST_F(AutoclickTest, DISABLED_WaitsToDrawAnimationAfterDwellBegins) { +TEST_F(AutoclickTest, WaitsToDrawAnimationAfterDwellBegins) { float ratio = GetAutoclickController()->GetStartGestureDelayRatioForTesting(); int full_delay = ceil(1.0 / ratio) * 5; int animation_delay = 5; @@ -626,9 +625,8 @@ Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false); } -TEST_F( - AutoclickTest, - DISABLED_StartsGestureOnTrayButtonButDoesNotClickIfMouseMovedWhenPaused) { +TEST_F(AutoclickTest, + StartsGestureOnTrayButtonButDoesNotClickIfMouseMovedWhenPaused) { Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true); GetAutoclickController()->set_revert_to_left_click(false); GetAutoclickController()->SetAutoclickEventType(
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc similarity index 93% rename from ash/app_list/home_launcher_gesture_handler.cc rename to ash/home_screen/home_launcher_gesture_handler.cc index 0a9ca90..a03895d9 100644 --- a/ash/app_list/home_launcher_gesture_handler.cc +++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" -#include "ash/app_list/app_list_controller_impl.h" -#include "ash/app_list/model/app_list_view_state.h" +#include "ash/home_screen/home_launcher_gesture_handler_observer.h" +#include "ash/home_screen/home_screen_controller.h" +#include "ash/home_screen/home_screen_delegate.h" #include "ash/root_window_controller.h" #include "ash/scoped_animation_disabler.h" #include "ash/screen_util.h" @@ -23,6 +24,7 @@ #include "ash/wm/workspace_controller.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/logging.h" #include "base/metrics/user_metrics.h" #include "base/numerics/ranges.h" #include "services/ws/public/mojom/window_tree_constants.mojom.h" @@ -270,9 +272,7 @@ DISALLOW_COPY_AND_ASSIGN(ScopedWindowModifier); }; -HomeLauncherGestureHandler::HomeLauncherGestureHandler( - AppListControllerImpl* app_list_controller) - : app_list_controller_(app_list_controller) { +HomeLauncherGestureHandler::HomeLauncherGestureHandler() { tablet_mode_observer_.Add(Shell::Get()->tablet_mode_controller()); } @@ -297,7 +297,7 @@ last_event_location_ = base::make_optional(location); if (mode != Mode::kNone) { - app_list_controller_->NotifyHomeLauncherTargetPositionChanged( + NotifyHomeLauncherTargetPositionChanged( mode == Mode::kSlideUpToShow /*showing*/, display_.id()); } @@ -402,6 +402,30 @@ return window2_->window(); } +void HomeLauncherGestureHandler::AddObserver( + HomeLauncherGestureHandlerObserver* observer) { + observers_.AddObserver(observer); +} + +void HomeLauncherGestureHandler::RemoveObserver( + HomeLauncherGestureHandlerObserver* observer) { + observers_.RemoveObserver(observer); +} + +void HomeLauncherGestureHandler::NotifyHomeLauncherTargetPositionChanged( + bool showing, + int64_t display_id) { + for (auto& observer : observers_) + observer.OnHomeLauncherTargetPositionChanged(showing, display_id); +} + +void HomeLauncherGestureHandler::NotifyHomeLauncherAnimationComplete( + bool shown, + int64_t display_id) { + for (auto& observer : observers_) + observer.OnHomeLauncherAnimationComplete(shown, display_id); +} + void HomeLauncherGestureHandler::OnWindowDestroying(aura::Window* window) { if (window1_ && window == GetWindow1()) { for (auto* hidden_window : hidden_windows_) @@ -440,10 +464,10 @@ } void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() { - float app_list_opacity = 1.f; + float home_launcher_opacity = 1.f; const bool is_final_state_show = IsFinalStateShow(); - app_list_controller_->NotifyHomeLauncherAnimationComplete( - is_final_state_show /*shown*/, display_.id()); + NotifyHomeLauncherAnimationComplete(is_final_state_show /*shown*/, + display_.id()); if (Shell::Get()->overview_controller()->IsSelecting()) { if (overview_active_on_gesture_start_ && is_final_state_show) { // Exit overview if event is released on the top half. This will also @@ -452,14 +476,18 @@ Shell::Get()->overview_controller()->ToggleOverview( OverviewSession::EnterExitOverviewType::kSwipeFromShelf); } else { - app_list_opacity = 0.f; + home_launcher_opacity = 0.f; } } + HomeScreenDelegate* home_screen_delegate = + Shell::Get()->home_screen_controller()->delegate(); + DCHECK(home_screen_delegate); + // Return the app list to its original opacity and transform without // animation. - app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( - 0, app_list_opacity, base::NullCallback()); + home_screen_delegate->UpdateYPositionAndOpacityForHomeLauncher( + 0, home_launcher_opacity, base::NullCallback()); if (!window1_) { RemoveObserversAndStopTracking(); @@ -477,8 +505,7 @@ window2_->ResetOpacityAndTransform(); if (is_final_state_show) { - // Show or hide the expand arrow view. - app_list_controller_->UpdateExpandArrowVisibility(); + home_screen_delegate->UpdateAfterHomeLauncherShown(); std::vector<aura::Window*> windows_to_hide_minimize; windows_to_hide_minimize.push_back(GetWindow1()); @@ -518,13 +545,11 @@ UpdateWindows(is_final_state_show ? 1.0 : 0.0, /*animate=*/true); if (!is_final_state_show && mode_ == Mode::kSlideDownToHide) { - app_list_controller_->NotifyHomeLauncherTargetPositionChanged( - false /*showing*/, display_.id()); + NotifyHomeLauncherTargetPositionChanged(false /*showing*/, display_.id()); base::RecordAction( base::UserMetricsAction("AppList_HomeLauncherToMRUWindow")); } else if (is_final_state_show && mode_ == Mode::kSlideUpToShow) { - app_list_controller_->NotifyHomeLauncherTargetPositionChanged( - true /*showing*/, display_.id()); + NotifyHomeLauncherTargetPositionChanged(true /*showing*/, display_.id()); base::RecordAction( base::UserMetricsAction("AppList_CurrentWindowToHomeLauncher")); } @@ -552,7 +577,10 @@ const int y_position = gfx::Tween::IntValueBetween( progress, work_area.bottom(), display_.bounds().y()); const float opacity = gfx::Tween::FloatValueBetween(progress, 0.f, 1.f); - app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( + HomeScreenDelegate* home_screen_delegate = + Shell::Get()->home_screen_controller()->delegate(); + DCHECK(home_screen_delegate); + home_screen_delegate->UpdateYPositionAndOpacityForHomeLauncher( y_position, opacity, animate ? base::BindRepeating(&HomeLauncherGestureHandler::UpdateSettings, base::Unretained(this))
diff --git a/ash/app_list/home_launcher_gesture_handler.h b/ash/home_screen/home_launcher_gesture_handler.h similarity index 90% rename from ash/app_list/home_launcher_gesture_handler.h rename to ash/home_screen/home_launcher_gesture_handler.h index 3846e055..60acede 100644 --- a/ash/app_list/home_launcher_gesture_handler.h +++ b/ash/home_screen/home_launcher_gesture_handler.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 ASH_APP_LIST_HOME_LAUNCHER_GESTURE_HANDLER_H_ -#define ASH_APP_LIST_HOME_LAUNCHER_GESTURE_HANDLER_H_ +#ifndef ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_H_ +#define ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_H_ #include <map> #include <vector> @@ -22,7 +22,7 @@ namespace ash { -class AppListControllerImpl; +class HomeLauncherGestureHandlerObserver; // HomeLauncherGestureHandler makes modifications to a window's transform and // opacity when gesture drag events are received and forwarded to it. @@ -45,8 +45,7 @@ kSlideDownToHide, }; - explicit HomeLauncherGestureHandler( - AppListControllerImpl* app_list_controller); + HomeLauncherGestureHandler(); ~HomeLauncherGestureHandler() override; // Called by owner of this object when a gesture event is received. |location| @@ -73,6 +72,13 @@ bool IsDragInProgress() const { return last_event_location_.has_value(); } + void AddObserver(HomeLauncherGestureHandlerObserver* observer); + void RemoveObserver(HomeLauncherGestureHandlerObserver* obsever); + + void NotifyHomeLauncherTargetPositionChanged(bool showing, + int64_t display_id); + void NotifyHomeLauncherAnimationComplete(bool shown, int64_t display_id); + // TODO(sammiequon): Investigate if it is needed to observe potential window // visibility changes, if they can happen. // aura::WindowObserver: @@ -170,15 +176,14 @@ ScopedObserver<TabletModeController, TabletModeObserver> tablet_mode_observer_{this}; - // Unowned and guaranteed to be non null for the lifetime of this. - AppListControllerImpl* app_list_controller_; - // The display where the windows are being processed. display::Display display_; + base::ObserverList<HomeLauncherGestureHandlerObserver> observers_; + DISALLOW_COPY_AND_ASSIGN(HomeLauncherGestureHandler); }; } // namespace ash -#endif // ASH_APP_LIST_HOME_LAUNCHER_GESTURE_HANDLER_H_ +#endif // ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_H_
diff --git a/ash/home_screen/home_launcher_gesture_handler_observer.h b/ash/home_screen/home_launcher_gesture_handler_observer.h new file mode 100644 index 0000000..6a94a85 --- /dev/null +++ b/ash/home_screen/home_launcher_gesture_handler_observer.h
@@ -0,0 +1,26 @@ +// Copyright 2019 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 ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_OBSERVER_H_ +#define ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_OBSERVER_H_ + +#include "base/observer_list_types.h" + +namespace ash { + +class HomeLauncherGestureHandlerObserver : public base::CheckedObserver { + public: + // Called when the HomeLauncher has started to be dragged, or a positional + // animation has begun. + virtual void OnHomeLauncherTargetPositionChanged(bool showing, + int64_t display_id) {} + + // Called when the HomeLauncher positional animation has completed. + virtual void OnHomeLauncherAnimationComplete(bool shown, int64_t display_id) { + } +}; + +} // namespace ash + +#endif // ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_OBSERVER_H_
diff --git a/ash/app_list/home_launcher_gesture_handler_unittest.cc b/ash/home_screen/home_launcher_gesture_handler_unittest.cc similarity index 98% rename from ash/app_list/home_launcher_gesture_handler_unittest.cc rename to ash/home_screen/home_launcher_gesture_handler_unittest.cc index 5bc6abc..16ce4d3 100644 --- a/ash/app_list/home_launcher_gesture_handler_unittest.cc +++ b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" -#include "ash/app_list/app_list_controller_impl.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/shelf_types.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" @@ -47,7 +47,9 @@ } HomeLauncherGestureHandler* GetGestureHandler() { - return Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + return Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler(); } void DoPress(Mode mode) {
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc new file mode 100644 index 0000000..daab566 --- /dev/null +++ b/ash/home_screen/home_screen_controller.cc
@@ -0,0 +1,21 @@ +// Copyright 2019 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 "ash/home_screen/home_screen_controller.h" + +#include "ash/home_screen/home_launcher_gesture_handler.h" + +namespace ash { + +HomeScreenController::HomeScreenController() + : home_launcher_gesture_handler_( + std::make_unique<HomeLauncherGestureHandler>()) {} + +HomeScreenController::~HomeScreenController() = default; + +void HomeScreenController::SetDelegate(HomeScreenDelegate* delegate) { + delegate_ = delegate; +} + +} // namespace ash
diff --git a/ash/home_screen/home_screen_controller.h b/ash/home_screen/home_screen_controller.h new file mode 100644 index 0000000..b9d6ea407 --- /dev/null +++ b/ash/home_screen/home_screen_controller.h
@@ -0,0 +1,48 @@ +// Copyright 2019 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 ASH_HOME_SCREEN_HOME_SCREEN_CONTROLLER_H_ +#define ASH_HOME_SCREEN_HOME_SCREEN_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace ash { + +class HomeLauncherGestureHandler; +class HomeScreenDelegate; + +// HomeScreenController handles the home launcher (e.g., tablet-mode app list) +// and owns the HomeLauncherGestureHandler that transitions the launcher window +// and other windows when the launcher is shown, hidden or animated. +class ASH_EXPORT HomeScreenController { + public: + HomeScreenController(); + ~HomeScreenController(); + + // Sets the delegate for home screen animations. + void SetDelegate(HomeScreenDelegate* delegate); + + HomeLauncherGestureHandler* home_launcher_gesture_handler() { + return home_launcher_gesture_handler_.get(); + } + + HomeScreenDelegate* delegate() { return delegate_; } + + private: + // Not owned. + HomeScreenDelegate* delegate_ = nullptr; + + // Owned pointer to the object which handles gestures related to the home + // launcher. + std::unique_ptr<HomeLauncherGestureHandler> home_launcher_gesture_handler_; + + DISALLOW_COPY_AND_ASSIGN(HomeScreenController); +}; + +} // namespace ash + +#endif // ASH_HOME_SCREEN_HOME_SCREEN_CONTROLLER_H_
diff --git a/ash/home_screen/home_screen_delegate.h b/ash/home_screen/home_screen_delegate.h new file mode 100644 index 0000000..314fbf9 --- /dev/null +++ b/ash/home_screen/home_screen_delegate.h
@@ -0,0 +1,37 @@ +// Copyright 2019 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 ASH_HOME_SCREEN_HOME_SCREEN_DELEGATE_H_ +#define ASH_HOME_SCREEN_HOME_SCREEN_DELEGATE_H_ + +#include "base/callback.h" +#include "ui/compositor/scoped_layer_animation_settings.h" + +namespace ash { + +// Delegate for implementation-specific home screen behavior. +class HomeScreenDelegate { + public: + // Callback which fills out the passed settings object, allowing the caller to + // animate with the given settings. + using UpdateAnimationSettingsCallback = + base::RepeatingCallback<void(ui::ScopedLayerAnimationSettings* settings, + bool observe)>; + + virtual ~HomeScreenDelegate() = default; + + // Updates the y position and opacity of the home launcher view. If |callback| + // is non-null, it should be called with animation settings. + virtual void UpdateYPositionAndOpacityForHomeLauncher( + int y_position_in_screen, + float opacity, + UpdateAnimationSettingsCallback callback) = 0; + + // Updates the home launcher view after its show animation has completed. + virtual void UpdateAfterHomeLauncherShown() = 0; +}; + +} // namespace ash + +#endif // ASH_HOME_SCREEN_HOME_SCREEN_DELEGATE_H_
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc index fec9ece..1f4e679 100644 --- a/ash/keyboard/virtual_keyboard_controller_unittest.cc +++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -43,21 +43,6 @@ VirtualKeyboardControllerTest() = default; ~VirtualKeyboardControllerTest() override = default; - void SetUp() override { - AshTestBase::SetUp(); - ws::InputDeviceClientTestApi().SetKeyboardDevices({}); - ws::InputDeviceClientTestApi().SetTouchscreenDevices({}); - keyboard_controller_ = keyboard::KeyboardController::Get(); - } - - void TearDown() override { - // Ensure inputs devices are reset for the next test. - ws::InputDeviceClientTestApi().SetKeyboardDevices({}); - ws::InputDeviceClientTestApi().SetTouchscreenDevices({}); - - AshTestBase::TearDown(); - } - display::Display GetPrimaryDisplay() { return display::Screen::GetScreen()->GetPrimaryDisplay(); } @@ -81,7 +66,9 @@ focusable_window->Focus(); } - keyboard::KeyboardController* keyboard_controller_ = nullptr; + keyboard::KeyboardController* keyboard_controller() { + return keyboard::KeyboardController::Get(); + } private: DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardControllerTest); @@ -136,7 +123,7 @@ client.last_keyset_); // Simulate the keyboard hiding. - if (keyboard_controller_->HasObserver(GetVirtualKeyboardController())) { + if (keyboard_controller()->HasObserver(GetVirtualKeyboardController())) { GetVirtualKeyboardController()->OnKeyboardHidden( false /* is_temporary_hide */); } @@ -161,33 +148,33 @@ Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr()); // Should show the keyboard by enabling it temporarily. - EXPECT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); - EXPECT_FALSE( - keyboard_controller_->IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled)); + EXPECT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); + EXPECT_FALSE(keyboard_controller()->IsEnableFlagSet( + KeyboardEnableFlag::kShelfEnabled)); GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset( chromeos::input_method::mojom::ImeKeyset::kEmoji); Shell::Get()->ime_controller()->FlushMojoForTesting(); - EXPECT_TRUE( - keyboard_controller_->IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled)); - EXPECT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_TRUE(keyboard_controller()->IsEnableFlagSet( + KeyboardEnableFlag::kShelfEnabled)); + EXPECT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Keyset should be emoji. EXPECT_EQ(chromeos::input_method::mojom::ImeKeyset::kEmoji, client.last_keyset_); // Simulate the keyboard hiding. - if (keyboard_controller_->HasObserver(GetVirtualKeyboardController())) { + if (keyboard_controller()->HasObserver(GetVirtualKeyboardController())) { GetVirtualKeyboardController()->OnKeyboardHidden( false /* is_temporary_hide */); } base::RunLoop().RunUntilIdle(); // The keyboard should still be disabled again. - EXPECT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); - EXPECT_FALSE( - keyboard_controller_->IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled)); + EXPECT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); + EXPECT_FALSE(keyboard_controller()->IsEnableFlagSet( + KeyboardEnableFlag::kShelfEnabled)); // Keyset should be reset to none. Shell::Get()->ime_controller()->FlushMojoForTesting(); @@ -206,25 +193,25 @@ chromeos::input_method::mojom::ImeKeyset::kEmoji); Shell::Get()->ime_controller()->FlushMojoForTesting(); - EXPECT_TRUE( - keyboard_controller_->IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled)); - EXPECT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_TRUE(keyboard_controller()->IsEnableFlagSet( + KeyboardEnableFlag::kShelfEnabled)); + EXPECT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Keyset should be emoji. EXPECT_EQ(chromeos::input_method::mojom::ImeKeyset::kEmoji, client.last_keyset_); // Simulate the keyboard hiding temporarily. - if (keyboard_controller_->HasObserver(GetVirtualKeyboardController())) { + if (keyboard_controller()->HasObserver(GetVirtualKeyboardController())) { GetVirtualKeyboardController()->OnKeyboardHidden( true /* is_temporary_hide */); } base::RunLoop().RunUntilIdle(); // The keyboard should still be enabled. - EXPECT_TRUE( - keyboard_controller_->IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled)); - EXPECT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_TRUE(keyboard_controller()->IsEnableFlagSet( + KeyboardEnableFlag::kShelfEnabled)); + EXPECT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Keyset should still be emoji. EXPECT_EQ(chromeos::input_method::mojom::ImeKeyset::kEmoji, @@ -283,13 +270,13 @@ keyboard_devices.push_back(ui::InputDevice( 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); // Remove the internal keyboard. Virtual keyboard should now show. ws::InputDeviceClientTestApi().SetKeyboardDevices({}); - EXPECT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Replug in the internal keyboard. Virtual keyboard should hide. ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - EXPECT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); } TEST_F(VirtualKeyboardControllerAutoTest, DisabledIfNoTouchScreen) { @@ -299,10 +286,10 @@ ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "Touchscreen", gfx::Size(800, 600), 0)); ws::InputDeviceClientTestApi().SetTouchscreenDevices(devices); - EXPECT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Remove touchscreen. Keyboard should hide. ws::InputDeviceClientTestApi().SetTouchscreenDevices({}); - EXPECT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + EXPECT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); } TEST_F(VirtualKeyboardControllerAutoTest, SuppressedIfExternalKeyboardPresent) { @@ -315,26 +302,26 @@ keyboard_devices.push_back( ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Toggle show keyboard. Keyboard should be visible. ResetObserver(); GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard(); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Toggle show keyboard. Keyboard should be hidden. ResetObserver(); GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard(); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Remove external keyboard. Should be notified that the keyboard is not // suppressed. ResetObserver(); ws::InputDeviceClientTestApi().SetKeyboardDevices({}); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_FALSE(IsVirtualKeyboardSuppressed()); } @@ -349,7 +336,7 @@ keyboards.push_back( ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboards); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); } // Tests tablet mode interaction without disabling the internal keyboard. @@ -363,13 +350,13 @@ keyboard_devices.push_back(ui::InputDevice( 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); // Toggle tablet mode on. TabletModeControllerTestApi().EnterTabletMode(); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); // Toggle tablet mode off. TabletModeControllerTestApi().LeaveTabletMode(); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); } // Tests that keyboard gets suppressed in tablet mode. @@ -387,19 +374,19 @@ ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); // Toggle tablet mode on. TabletModeControllerTestApi().EnterTabletMode(); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Toggle show keyboard. Keyboard should be visible. ResetObserver(); GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard(); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Toggle show keyboard. Keyboard should be hidden. ResetObserver(); GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard(); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_TRUE(IsVirtualKeyboardSuppressed()); // Remove external keyboard. Should be notified that the keyboard is not @@ -407,12 +394,12 @@ ResetObserver(); keyboard_devices.pop_back(); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); ASSERT_TRUE(notified()); ASSERT_FALSE(IsVirtualKeyboardSuppressed()); // Toggle tablet mode oFF. TabletModeControllerTestApi().LeaveTabletMode(); - ASSERT_FALSE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_FALSE(keyboard_controller()->IsKeyboardEnableRequested()); } class VirtualKeyboardControllerAlwaysEnabledTest @@ -444,7 +431,7 @@ keyboard_devices.push_back( ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); - ASSERT_TRUE(keyboard_controller_->IsKeyboardEnableRequested()); + ASSERT_TRUE(keyboard_controller()->IsKeyboardEnableRequested()); } // Test for http://crbug.com/297858. |GetContainerForDefaultDisplay| should @@ -594,10 +581,10 @@ UpdateDisplay("500x500,500x500"); // Show in secondary display. - keyboard_controller_->ShowKeyboardInDisplay(GetSecondaryDisplay()); - EXPECT_EQ(GetSecondaryRootWindow(), keyboard_controller_->GetRootWindow()); + keyboard_controller()->ShowKeyboardInDisplay(GetSecondaryDisplay()); + EXPECT_EQ(GetSecondaryRootWindow(), keyboard_controller()->GetRootWindow()); ASSERT_TRUE(keyboard::WaitUntilShown()); - EXPECT_TRUE(!keyboard_controller_->GetKeyboardWindow()->bounds().IsEmpty()); + EXPECT_TRUE(!keyboard_controller()->GetKeyboardWindow()->bounds().IsEmpty()); } } // namespace ash
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc index d676e35..05c2970 100644 --- a/ash/login/login_screen_controller.cc +++ b/ash/login/login_screen_controller.cc
@@ -485,11 +485,13 @@ } void LoginScreenController::SetKioskApps( - std::vector<mojom::KioskAppInfoPtr> kiosk_apps) { + std::vector<mojom::KioskAppInfoPtr> kiosk_apps, + SetKioskAppsCallback callback) { Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow()) ->shelf_widget() ->login_shelf_view() ->SetKioskApps(std::move(kiosk_apps)); + std::move(callback).Run(true); } void LoginScreenController::ShowKioskAppError(const std::string& message) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h index f177af2..ffba8952 100644 --- a/ash/login/login_screen_controller.h +++ b/ash/login/login_screen_controller.h
@@ -5,6 +5,8 @@ #ifndef ASH_LOGIN_LOGIN_SCREEN_CONTROLLER_H_ #define ASH_LOGIN_LOGIN_SCREEN_CONTROLLER_H_ +#include <vector> + #include "ash/ash_export.h" #include "ash/login/login_screen_controller_observer.h" #include "ash/public/cpp/system_tray_focus_observer.h" @@ -158,7 +160,8 @@ std::vector<mojom::InputMethodItemPtr> keyboard_layouts) override; void SetPublicSessionShowFullManagementDisclosure( bool is_full_management_disclosure_needed) override; - void SetKioskApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps) override; + void SetKioskApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps, + SetKioskAppsCallback callback) override; void ShowKioskAppError(const std::string& message) override; void NotifyOobeDialogState(mojom::OobeDialogState state) override; void SetAddUserButtonEnabled(bool enable) override;
diff --git a/ash/login/login_screen_test_api.cc b/ash/login/login_screen_test_api.cc index 41deee0..9cdbc73 100644 --- a/ash/login/login_screen_test_api.cc +++ b/ash/login/login_screen_test_api.cc
@@ -6,6 +6,7 @@ #include <memory> #include <utility> +#include <vector> #include "ash/login/ui/lock_contents_view.h" #include "ash/login/ui/lock_screen.h" @@ -44,6 +45,75 @@ } // anonymous namespace +class ShelfTestUiUpdateDelegate : public LoginShelfView::TestUiUpdateDelegate { + public: + using Callback = mojom::LoginScreenTestApi::WaitForUiUpdateCallback; + + // Returns instance owned by LoginShelfView. Installs instance of + // ShelfTestUiUpdateDelegate when needed. + static ShelfTestUiUpdateDelegate* Get(LoginShelfView* shelf) { + if (!shelf->test_ui_update_delegate()) { + shelf->InstallTestUiUpdateDelegate( + std::make_unique<ShelfTestUiUpdateDelegate>()); + } + return static_cast<ShelfTestUiUpdateDelegate*>( + shelf->test_ui_update_delegate()); + } + + ShelfTestUiUpdateDelegate() = default; + ~ShelfTestUiUpdateDelegate() override { + for (PendingCallback& entry : heap_) + std::move(entry.callback).Run(false); + } + + // Returns UI update count. + int64_t ui_update_count() const { return ui_update_count_; } + + // Add a callback to be invoked when ui update count is greater than + // |previous_update_count|. Note |callback| could be invoked synchronously + // when the current ui update count is already greater than + // |previous_update_count|. + void AddCallback(int64_t previous_update_count, Callback callback) { + if (previous_update_count < ui_update_count_) { + std::move(callback).Run(true); + } else { + heap_.emplace_back(previous_update_count, std::move(callback)); + std::push_heap(heap_.begin(), heap_.end()); + } + } + + // LoginShelfView::TestUiUpdateDelegate + void OnUiUpdate() override { + ++ui_update_count_; + while (!heap_.empty() && heap_.front().old_count < ui_update_count_) { + std::move(heap_.front().callback).Run(true); + std::pop_heap(heap_.begin(), heap_.end()); + heap_.pop_back(); + } + } + + private: + struct PendingCallback { + PendingCallback(int64_t old_count, Callback callback) + : old_count(old_count), callback(std::move(callback)) {} + + bool operator<(const PendingCallback& right) const { + // We need min_heap, therefore this returns true when another element on + // the right is less than this count. (regular heap is max_heap). + return old_count > right.old_count; + } + + int64_t old_count = 0; + Callback callback; + }; + + std::vector<PendingCallback> heap_; + + int64_t ui_update_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(ShelfTestUiUpdateDelegate); +}; + // static void LoginScreenTestApi::BindRequest(mojom::LoginScreenTestApiRequest request) { mojo::MakeStrongBinding(std::make_unique<LoginScreenTestApi>(), @@ -105,7 +175,33 @@ void LoginScreenTestApi::GetUiUpdateCount(GetUiUpdateCountCallback callback) { LoginShelfView* view = GetLoginShelfView(); - std::move(callback).Run(view ? view->ui_update_count() : 0); + std::move(callback).Run( + view ? ShelfTestUiUpdateDelegate::Get(view)->ui_update_count() : 0); +} + +void LoginScreenTestApi::LaunchApp(const std::string& app_id, + LaunchAppCallback callback) { + LoginShelfView* view = GetLoginShelfView(); + + std::move(callback).Run(view && view->LaunchAppForTesting(app_id)); +} + +void LoginScreenTestApi::ClickAddUserButton( + ClickAddUserButtonCallback callback) { + LoginShelfView* view = GetLoginShelfView(); + + std::move(callback).Run(view && view->SimulateAddUserButtonForTesting()); +} + +void LoginScreenTestApi::WaitForUiUpdate(int64_t previous_update_count, + WaitForUiUpdateCallback callback) { + LoginShelfView* view = GetLoginShelfView(); + if (view) { + ShelfTestUiUpdateDelegate::Get(view)->AddCallback(previous_update_count, + std::move(callback)); + } else { + std::move(callback).Run(false); + } } } // namespace ash
diff --git a/ash/login/login_screen_test_api.h b/ash/login/login_screen_test_api.h index a61a35c..907881df 100644 --- a/ash/login/login_screen_test_api.h +++ b/ash/login/login_screen_test_api.h
@@ -5,6 +5,8 @@ #ifndef ASH_LOGIN_LOGIN_SCREEN_TEST_API_H_ #define ASH_LOGIN_LOGIN_SCREEN_TEST_API_H_ +#include <string> + #include "ash/public/interfaces/login_screen_test_api.test-mojom.h" #include "base/macros.h" #include "components/account_id/account_id.h" @@ -29,6 +31,16 @@ const std::string& password, SubmitPasswordCallback callback) override; void GetUiUpdateCount(GetUiUpdateCountCallback callback) override; + void LaunchApp(const std::string& app_id, + LaunchAppCallback callback) override; + void ClickAddUserButton(ClickAddUserButtonCallback callback) override; + // This blocks until UI update number becomes greater than the + // |previous_update_count|. Where |previous_update_count| presumably is + // coming from GetUiUpdateCount(). This way test remembers the "current" UI + // update version, performs some actions, and then waits until UI switches to + // the new version. + void WaitForUiUpdate(int64_t previous_update_count, + WaitForUiUpdateCallback callback) override; private: DISALLOW_COPY_AND_ASSIGN(LoginScreenTestApi);
diff --git a/ash/metrics/pointer_metrics_recorder.cc b/ash/metrics/pointer_metrics_recorder.cc index 85e00e1..2ae3082 100644 --- a/ash/metrics/pointer_metrics_recorder.cc +++ b/ash/metrics/pointer_metrics_recorder.cc
@@ -29,18 +29,38 @@ // Find the input type, form factor and destination combination of the down // event. Used to get the UMA histogram bucket. -DownEventMetric FindCombination(DownEventSource input_type, - DownEventFormFactor form_factor, - int destination) { +DownEventMetric FindCombinationDeprecated(DownEventSource input_type, + DownEventFormFactor form_factor, + int destination) { + if (destination == static_cast<int>(AppType::CROSTINI_APP)) + destination = static_cast<int>(AppType::OTHERS); + constexpr int kAppCountDeprecated = kAppCount - 1; int num_combination_per_input = - kAppCount * static_cast<int>(DownEventFormFactor::kFormFactorCount); + kAppCountDeprecated * + static_cast<int>(DownEventFormFactor::kFormFactorCount); int result = static_cast<int>(input_type) * num_combination_per_input + - static_cast<int>(form_factor) * kAppCount + destination; + static_cast<int>(form_factor) * kAppCountDeprecated + + destination; DCHECK(result >= 0 && result < static_cast<int>(DownEventMetric::kCombinationCount)); return static_cast<DownEventMetric>(result); } +DownEventMetric2 FindCombination(int destination, + DownEventSource input_type, + DownEventFormFactor form_factor) { + constexpr int kNumCombinationPerDestination = + static_cast<int>(DownEventSource::kSourceCount) * + static_cast<int>(DownEventFormFactor::kFormFactorCount); + int result = destination * kNumCombinationPerDestination + + static_cast<int>(DownEventFormFactor::kFormFactorCount) * + static_cast<int>(input_type) + + static_cast<int>(form_factor); + DCHECK(result >= 0 && + result <= static_cast<int>(DownEventMetric2::kMaxValue)); + return static_cast<DownEventMetric2>(result); +} + void RecordUMA(ui::EventPointerType type, ui::EventTarget* event_target) { DCHECK_NE(type, ui::EventPointerType::POINTER_TYPE_UNKNOWN); views::Widget* target = views::Widget::GetTopLevelWidgetForNativeView( @@ -79,8 +99,13 @@ UMA_HISTOGRAM_ENUMERATION( "Event.DownEventCount.PerInputFormFactorDestinationCombination", - FindCombination(input_type, form_factor, GetDestination(target)), + FindCombinationDeprecated(input_type, form_factor, + GetDestination(target)), DownEventMetric::kCombinationCount); + + UMA_HISTOGRAM_ENUMERATION( + "Event.DownEventCount.PerInputFormFactorDestinationCombination2", + FindCombination(GetDestination(target), input_type, form_factor)); } } // namespace
diff --git a/ash/metrics/pointer_metrics_recorder.h b/ash/metrics/pointer_metrics_recorder.h index bacc4da3..3532421 100644 --- a/ash/metrics/pointer_metrics_recorder.h +++ b/ash/metrics/pointer_metrics_recorder.h
@@ -32,6 +32,74 @@ kSourceCount, }; +// App type (Destination), Input and FormFactor Combination of the down event. +// This enum is used to back an UMA histogram and new values should +// be inserted immediately above kCombinationCount. +enum class DownEventMetric2 { + // All "Unknown" types are deprecated, never occur in practice. + kOthersUnknownClamshell = 0, + kOthersUnknownTabletLandscape = 1, + kOthersUnknownTabletPortrait = 2, + kOthersMouseClamshell = 3, + kOthersMouseTabletLandscape = 4, + kOthersMouseTabletPortrait = 5, + kOthersStylusClamshell = 6, + kOthersStylusTabletLandscape = 7, + kOthersStylusTabletPortrait = 8, + kOthersTouchClamshell = 9, + kOthersTouchTabletLandscape = 10, + kOthersTouchTabletPortrait = 11, + kBrowserUnknownClamshell = 12, + kBrowserUnknownTabletLandscape = 13, + kBrowserUnknownTabletPortrait = 14, + kBrowserMouseClamshell = 15, + kBrowserMouseTabletLandscape = 16, + kBrowserMouseTabletPortrait = 17, + kBrowserStylusClamshell = 18, + kBrowserStylusTabletLandscape = 19, + kBrowserStylusTabletPortrait = 20, + kBrowserTouchClamshell = 21, + kBrowserTouchTabletLandscape = 22, + kBrowserTouchTabletPortrait = 23, + kChromeAppUnknownClamshell = 24, + kChromeAppUnknownTabletLandscape = 25, + kChromeAppUnknownTabletPortrait = 26, + kChromeAppMouseClamshell = 27, + kChromeAppMouseTabletLandscape = 28, + kChromeAppMouseTabletPortrait = 29, + kChromeAppStylusClamshell = 30, + kChromeAppStylusTabletLandscape = 31, + kChromeAppStylusTabletPortrait = 32, + kChromeAppTouchClamshell = 33, + kChromeAppTouchTabletLandscape = 34, + kChromeAppTouchTabletPortrait = 35, + kArcAppUnknownClamshell = 36, + kArcAppUnknownTabletLandscape = 37, + kArcAppUnknownTabletPortrait = 38, + kArcAppMouseClamshell = 39, + kArcAppMouseTabletLandscape = 40, + kArcAppMouseTabletPortrait = 41, + kArcAppStylusClamshell = 42, + kArcAppStylusTabletLandscape = 43, + kArcAppStylusTabletPortrait = 44, + kArcAppTouchClamshell = 45, + kArcAppTouchTabletLandscape = 46, + kArcAppTouchTabletPortrait = 47, + kCrostiniAppUnknownClamshell = 48, + kCrostiniAppUnknownTabletLandscape = 49, + kCrostiniAppUnknownTabletPortrait = 50, + kCrostiniAppMouseClamshell = 51, + kCrostiniAppMouseTabletLandscape = 52, + kCrostiniAppMouseTabletPortrait = 53, + kCrostiniAppStylusClamshell = 54, + kCrostiniAppStylusTabletLandscape = 55, + kCrostiniAppStylusTabletPortrait = 56, + kCrostiniAppTouchClamshell = 57, + kCrostiniAppTouchTabletLandscape = 58, + kCrostiniAppTouchTabletPortrait = 59, + kMaxValue = kCrostiniAppTouchTabletPortrait +}; + // Input, FormFactor, and Destination Combination of the down event. // This enum is used to back an UMA histogram and new values should // be inserted immediately above kCombinationCount.
diff --git a/ash/metrics/pointer_metrics_recorder_unittest.cc b/ash/metrics/pointer_metrics_recorder_unittest.cc index f479e54..d24aa697 100644 --- a/ash/metrics/pointer_metrics_recorder_unittest.cc +++ b/ash/metrics/pointer_metrics_recorder_unittest.cc
@@ -20,9 +20,12 @@ namespace ash { namespace { -const char kCombinationHistogramName[] = +const char kCombinationDeprecatedHistogramName[] = "Event.DownEventCount.PerInputFormFactorDestinationCombination"; +const char kCombinationHistogramName[] = + "Event.DownEventCount.PerInputFormFactorDestinationCombination2"; + // Test fixture for the PointerMetricsRecorder class. class PointerMetricsRecorderTest : public AshTestBase { public: @@ -116,7 +119,7 @@ base::TimeTicks(), 0, 0); pointer_metrics_recorder_->OnMouseEvent(&mouse_up); - histogram_tester_->ExpectTotalCount(kCombinationHistogramName, 0); + histogram_tester_->ExpectTotalCount(kCombinationDeprecatedHistogramName, 0); } // Verifies that down events from different combination of input type, form @@ -131,225 +134,518 @@ DownEventFormFactor::kClamshell, AppType::OTHERS); histogram_tester_->ExpectBucketCount( kCombinationHistogramName, - static_cast<int>(DownEventMetric::kMouseClamshellOthers), 1); - - CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, - DownEventFormFactor::kClamshell, AppType::BROWSER); - histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, - static_cast<int>(DownEventMetric::kMouseClamshellBrowser), 1); - - CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, - DownEventFormFactor::kClamshell, AppType::CHROME_APP); - histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, - static_cast<int>(DownEventMetric::kMouseClamshellChromeApp), 1); - - CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, - DownEventFormFactor::kClamshell, AppType::ARC_APP); - histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, - static_cast<int>(DownEventMetric::kMouseClamshellArcApp), 1); + static_cast<int>(DownEventMetric2::kOthersMouseClamshell), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); histogram_tester_->ExpectBucketCount( kCombinationHistogramName, - static_cast<int>(DownEventMetric::kMouseTabletLandscapeOthers), 1); + static_cast<int>(DownEventMetric2::kOthersMouseTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersMouseTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kClamshell, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kClamshell, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kOthersStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserMouseClamshell), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); histogram_tester_->ExpectBucketCount( kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserMouseTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserMouseTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kClamshell, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kClamshell, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kBrowserStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppMouseClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModeLandscape, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppMouseTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModePortrait, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppMouseTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kClamshell, AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModeLandscape, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModePortrait, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kClamshell, AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModeLandscape, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModePortrait, + AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kChromeAppStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppMouseClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppMouseTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppMouseTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kClamshell, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kClamshell, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kArcAppStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppMouseClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModeLandscape, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppMouseTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModePortrait, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppMouseTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kClamshell, AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModeLandscape, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, + DownEventFormFactor::kTabletModePortrait, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusTabletPortrait), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kClamshell, AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusClamshell), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModeLandscape, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusTabletLandscape), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, + DownEventFormFactor::kTabletModePortrait, + AppType::CROSTINI_APP); + histogram_tester_->ExpectBucketCount( + kCombinationHistogramName, + static_cast<int>(DownEventMetric2::kCrostiniAppStylusTabletPortrait), 1); + + histogram_tester_->ExpectTotalCount(kCombinationHistogramName, 45); +} + +// Verifies that down events from different combination of input type, form +// factor and destination are recorded. +TEST_F(PointerMetricsRecorderTest, DownEventPerCombinationDeprecated) { + int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); + display::DisplayManager* display_manager = Shell::Get()->display_manager(); + display::test::ScopedSetInternalDisplayId set_internal(display_manager, + display_id); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, + static_cast<int>(DownEventMetric::kMouseClamshellOthers), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, + static_cast<int>(DownEventMetric::kMouseClamshellBrowser), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::CHROME_APP); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, + static_cast<int>(DownEventMetric::kMouseClamshellChromeApp), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kClamshell, AppType::ARC_APP); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, + static_cast<int>(DownEventMetric::kMouseClamshellArcApp), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, + static_cast<int>(DownEventMetric::kMouseTabletLandscapeOthers), 1); + + CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, + DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); + histogram_tester_->ExpectBucketCount( + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletLandscapeBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModeLandscape, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletLandscapeChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletLandscapeArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletPortraitOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletPortraitBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModePortrait, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletPortraitChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_MOUSE, DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kMouseTabletPortraitArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kClamshell, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kClamshell, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kClamshell, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kClamshell, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModeLandscape, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModePortrait, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_PEN, DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kClamshell, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kClamshell, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kClamshell, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kClamshell, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusClamshellArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModeLandscape, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModeLandscape, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModeLandscape, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModeLandscape, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletLandscapeArcApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModePortrait, AppType::OTHERS); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitOthers), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModePortrait, AppType::BROWSER); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitBrowser), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModePortrait, AppType::CHROME_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitChromeApp), 1); CreateDownEvent(ui::EventPointerType::POINTER_TYPE_TOUCH, DownEventFormFactor::kTabletModePortrait, AppType::ARC_APP); histogram_tester_->ExpectBucketCount( - kCombinationHistogramName, + kCombinationDeprecatedHistogramName, static_cast<int>(DownEventMetric::kStylusTabletPortraitArcApp), 1); - histogram_tester_->ExpectTotalCount(kCombinationHistogramName, 36); + histogram_tester_->ExpectTotalCount(kCombinationDeprecatedHistogramName, 36); } } // namespace ash
diff --git a/ash/mus_property_mirror_ash_unittest.cc b/ash/mus_property_mirror_ash_unittest.cc index 16d1783..e664dfd 100644 --- a/ash/mus_property_mirror_ash_unittest.cc +++ b/ash/mus_property_mirror_ash_unittest.cc
@@ -59,18 +59,6 @@ *window_2->GetProperty(aura::client::kTitleKey)); EXPECT_NE(window_1->GetProperty(aura::client::kTitleKey), window_2->GetProperty(aura::client::kTitleKey)); - - window_1->ClearProperty(aura::client::kWindowIconKey); - EXPECT_EQ(nullptr, window_1->GetProperty(aura::client::kWindowIconKey)); - window_2->ClearProperty(aura::client::kWindowIconKey); - EXPECT_EQ(nullptr, window_2->GetProperty(aura::client::kWindowIconKey)); - window_1->SetProperty(aura::client::kWindowIconKey, new gfx::ImageSkia()); - EXPECT_NE(nullptr, window_1->GetProperty(aura::client::kWindowIconKey)); - mus_property_mirror_ash.MirrorPropertyFromWidgetWindowToRootWindow( - window_1.get(), window_2.get(), aura::client::kWindowIconKey); - EXPECT_NE(nullptr, window_2->GetProperty(aura::client::kWindowIconKey)); - EXPECT_NE(window_1->GetProperty(aura::client::kWindowIconKey), - window_2->GetProperty(aura::client::kWindowIconKey)); } } // namespace ash
diff --git a/ash/public/cpp/app_types.h b/ash/public/cpp/app_types.h index 005f5f8..f68e777 100644 --- a/ash/public/cpp/app_types.h +++ b/ash/public/cpp/app_types.h
@@ -16,7 +16,8 @@ BROWSER, CHROME_APP, ARC_APP, - APP_TYPE_LAST = ARC_APP, + CROSTINI_APP, + APP_TYPE_LAST = CROSTINI_APP, }; const int kAppCount = static_cast<int>(AppType::APP_TYPE_LAST) + 1;
diff --git a/ash/public/cpp/mus_property_mirror_ash.cc b/ash/public/cpp/mus_property_mirror_ash.cc index 2792c80a..f2c7f20 100644 --- a/ash/public/cpp/mus_property_mirror_ash.cc +++ b/ash/public/cpp/mus_property_mirror_ash.cc
@@ -50,8 +50,6 @@ } else if (key == kWindowPinTypeKey) { ash::mojom::WindowPinType value = window->GetProperty(kWindowPinTypeKey); root_window->SetProperty(kWindowPinTypeKey, value); - } else if (key == aura::client::kAppIconKey) { - MirrorOwnedProperty(window, root_window, aura::client::kAppIconKey); } else if (key == kRestoreBoundsOverrideKey) { MirrorOwnedProperty(window, root_window, kRestoreBoundsOverrideKey); } else if (key == kRestoreWindowStateTypeOverrideKey) { @@ -73,9 +71,6 @@ } else if (key == aura::client::kTopViewInset) { root_window->SetProperty(aura::client::kTopViewInset, window->GetProperty(aura::client::kTopViewInset)); - - } else if (key == aura::client::kWindowIconKey) { - MirrorOwnedProperty(window, root_window, aura::client::kWindowIconKey); } else if (key == kFrameActiveColorKey) { root_window->SetProperty(kFrameActiveColorKey, window->GetProperty(kFrameActiveColorKey));
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom index 764af8ed..923832c 100644 --- a/ash/public/interfaces/login_screen.mojom +++ b/ash/public/interfaces/login_screen.mojom
@@ -195,7 +195,8 @@ bool show_full_management_disclosure); // Update the kiosk app data for the login screen. - SetKioskApps(array<KioskAppInfo> kiosk_apps); + // Returns true on success. + SetKioskApps(array<KioskAppInfo> kiosk_apps) => (bool success); // Display a toast describing the latest kiosk app launch error. ShowKioskAppError(string message);
diff --git a/ash/public/interfaces/login_screen_test_api.test-mojom b/ash/public/interfaces/login_screen_test_api.test-mojom index 1b1393dd..3598b59 100644 --- a/ash/public/interfaces/login_screen_test_api.test-mojom +++ b/ash/public/interfaces/login_screen_test_api.test-mojom
@@ -25,4 +25,16 @@ // Fetches current UI update count. GetUiUpdateCount() => (int64 count); + + // Simulates Kiosk App launch. Returns true if launch attempt was successful. + // (I.e. app was found, and launch event was generated.) + LaunchApp(string app_id) => (bool found); + + // Simulate Click on AddUser button. + // Returns true if request was successful. + ClickAddUserButton() => (bool success); + + // Blocks until UI update counter is greated than |previous_update_count|. + // Returns true on success, false on error. + WaitForUiUpdate(int64 previous_update_count) => (bool success); };
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc index f175e78f..7482844 100644 --- a/ash/shelf/login_shelf_view.cc +++ b/ash/shelf/login_shelf_view.cc
@@ -4,7 +4,9 @@ #include "ash/shelf/login_shelf_view.h" +#include <algorithm> #include <memory> +#include <string> #include <utility> #include "ash/focus_cycler.h" @@ -18,7 +20,6 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" -#include "ash/session/session_observer.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_constants.h" #include "ash/shelf/shelf_widget.h" @@ -31,6 +32,8 @@ #include "ash/system/tray/tray_popup_utils.h" #include "ash/tray_action/tray_action.h" #include "ash/wm/lock_state_controller.h" +#include "base/bind.h" +#include "base/callback_helpers.h" #include "base/metrics/user_metrics.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "skia/ext/image_operations.h" @@ -126,8 +129,7 @@ GetButtonHighlightPath(view).release()); } -class LoginShelfButton : public views::LabelButton, - public ash::SessionObserver { +class LoginShelfButton : public views::LabelButton { public: LoginShelfButton(views::ButtonListener* listener, const base::string16& text, @@ -157,9 +159,7 @@ SetTextSubpixelRenderingEnabled(false); SetImageLabelSpacing(kImageLabelSpacingDp); - SetTextColor(views::Button::STATE_NORMAL, kButtonTextColor); - SetTextColor(views::Button::STATE_HOVERED, kButtonTextColor); - SetTextColor(views::Button::STATE_PRESSED, kButtonTextColor); + SetEnabledTextColors(kButtonTextColor); SetTextColor( views::Button::STATE_DISABLED, SkColorSetA(kButtonTextColor, login_constants::kButtonDisabledAlpha)); @@ -195,30 +195,29 @@ return ink_drop; } - // ash::SessionObserver: - void OnSessionStateChanged(session_manager::SessionState state) override { - if (state == session_manager::SessionState::OOBE) { - SetTextColor(views::Button::STATE_NORMAL, gfx::kGoogleGrey600); - SetTextColor(views::Button::STATE_HOVERED, gfx::kGoogleGrey600); - SetTextColor(views::Button::STATE_PRESSED, gfx::kGoogleGrey600); - SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(icon_, gfx::kGoogleGrey600)); - } else { - SetTextColor(views::Button::STATE_NORMAL, kButtonTextColor); - SetTextColor(views::Button::STATE_HOVERED, kButtonTextColor); - SetTextColor(views::Button::STATE_PRESSED, kButtonTextColor); - SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(icon_, kButtonTextColor)); - } + void PaintDarkColors() { + SetEnabledTextColors(gfx::kGoogleGrey600); + SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(icon_, gfx::kGoogleGrey600)); + } + + void PaintLightColors() { + SetEnabledTextColors(kButtonTextColor); + SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(icon_, kButtonTextColor)); } private: - ash::ScopedSessionObserver observer_{this}; const gfx::VectorIcon& icon_; DISALLOW_COPY_AND_ASSIGN(LoginShelfButton); }; +void StartAddUser() { + Shell::Get()->login_screen_controller()->ShowGaiaSignin( + true /*can_close*/, base::nullopt /*prefilled_account*/); +} + } // namespace class KioskAppsButton : public views::MenuButton, @@ -226,8 +225,9 @@ public ui::SimpleMenuModel, public ui::SimpleMenuModel::Delegate { public: - KioskAppsButton(const base::string16& text, const gfx::ImageSkia& image) - : MenuButton(text, this), ui::SimpleMenuModel(this) { + KioskAppsButton() + : MenuButton(l10n_util::GetStringUTF16(IDS_ASH_SHELF_APPS_BUTTON), this), + ui::SimpleMenuModel(this) { SetFocusBehavior(FocusBehavior::ALWAYS); SetInstallFocusRingOnFocus(true); focus_ring()->SetColor(kFocusBorderColor); @@ -244,15 +244,25 @@ SetTextSubpixelRenderingEnabled(false); - SetImage(views::Button::STATE_NORMAL, image); + SetImage(views::Button::STATE_NORMAL, + CreateVectorIcon(kShelfAppsButtonIcon, kButtonIconColor)); SetImageLabelSpacing(kImageLabelSpacingDp); - SetTextColor(views::Button::STATE_NORMAL, kButtonTextColor); - SetTextColor(views::Button::STATE_HOVERED, kButtonTextColor); - SetTextColor(views::Button::STATE_PRESSED, kButtonTextColor); + SetEnabledTextColors(kButtonTextColor); label()->SetFontList(views::Label::GetDefaultFontList().Derive( 1, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL)); } + bool LaunchAppForTesting(const std::string& app_id) { + for (size_t i = 0; i < kiosk_apps_.size(); ++i) { + if (kiosk_apps_[i]->identifier->get_app_id() != app_id) + continue; + + ExecuteCommand(i, 0); + return true; + } + return false; + } + // Replace the existing items list with a new list of kiosk app menu items. void SetApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps) { kiosk_apps_ = std::move(kiosk_apps); @@ -300,6 +310,18 @@ return ink_drop; } + void PaintDarkColors() { + SetEnabledTextColors(gfx::kGoogleGrey600); + SetImage(views::Button::STATE_NORMAL, + CreateVectorIcon(kShelfAppsButtonIcon, gfx::kGoogleGrey600)); + } + + void PaintLightColors() { + SetEnabledTextColors(kButtonTextColor); + SetImage(views::Button::STATE_NORMAL, + CreateVectorIcon(kShelfAppsButtonIcon, kButtonIconColor)); + } + // views::MenuButtonListener: void OnMenuButtonClicked(MenuButton* source, const gfx::Point& point, @@ -353,6 +375,8 @@ DISALLOW_COPY_AND_ASSIGN(KioskAppsButton); }; +LoginShelfView::TestUiUpdateDelegate::~TestUiUpdateDelegate() = default; + LoginShelfView::LoginShelfView( LockScreenActionBackgroundController* lock_screen_action_background) : lock_screen_action_background_(lock_screen_action_background), @@ -376,9 +400,7 @@ }; add_button(kShutdown, IDS_ASH_SHELF_SHUTDOWN_BUTTON, kShelfShutdownButtonIcon); - kiosk_apps_button_ = new KioskAppsButton( - l10n_util::GetStringUTF16(IDS_ASH_SHELF_APPS_BUTTON), - CreateVectorIcon(kShelfAppsButtonIcon, kButtonIconColor)); + kiosk_apps_button_ = new KioskAppsButton(); kiosk_apps_button_->set_id(kApps); AddChildView(kiosk_apps_button_); add_button(kRestart, IDS_ASH_SHELF_RESTART_BUTTON, kShelfShutdownButtonIcon); @@ -484,8 +506,7 @@ Shell::Get()->login_screen_controller()->LoginAsGuest(); break; case kAddUser: - Shell::Get()->login_screen_controller()->ShowGaiaSignin( - true /*can_close*/, base::nullopt /*prefilled_account*/); + StartAddUser(); break; case kParentAccess: Shell::Get()->login_screen_controller()->SetShowParentAccessDialog(true); @@ -495,6 +516,26 @@ } } +bool LoginShelfView::LaunchAppForTesting(const std::string& app_id) { + return kiosk_apps_button_->enabled() && + kiosk_apps_button_->LaunchAppForTesting(app_id); +} + +bool LoginShelfView::SimulateAddUserButtonForTesting() { + views::View* add_user_button = GetViewByID(kAddUser); + if (!add_user_button->enabled()) + return false; + + StartAddUser(); + return true; +} + +void LoginShelfView::InstallTestUiUpdateDelegate( + std::unique_ptr<TestUiUpdateDelegate> delegate) { + DCHECK(!test_ui_update_delegate_.get()); + test_ui_update_delegate_ = std::move(delegate); +} + void LoginShelfView::SetKioskApps( std::vector<mojom::KioskAppInfoPtr> kiosk_apps) { kiosk_apps_button_->SetApps(std::move(kiosk_apps)); @@ -561,6 +602,14 @@ } void LoginShelfView::UpdateUi() { + // Make sure observers are notified. + base::ScopedClosureRunner fire_observer(base::BindOnce( + [](LoginShelfView* self) { + if (self->test_ui_update_delegate()) + self->test_ui_update_delegate()->OnUiUpdate(); + }, + base::Unretained(this))); + SessionState session_state = Shell::Get()->session_controller()->GetSessionState(); if (session_state == SessionState::ACTIVE) { @@ -568,9 +617,9 @@ // to avoid affecting calculation of the shelf size. for (int i = 0; i < child_count(); ++i) child_at(i)->SetVisible(false); + return; } - ++ui_update_count_; bool show_reboot = Shell::Get()->shutdown_controller()->reboot_on_shutdown(); mojom::TrayActionState tray_action_state = Shell::Get()->tray_action()->GetLockScreenNoteState(); @@ -580,7 +629,7 @@ tray_action_state == mojom::TrayActionState::kLaunching) && !LockScreenActionBackgroundAnimating(); - // The following should be kept in sync with |updateUI_| in md_header_bar.js. + // TODO: https://crbug.com/935849 GetViewByID(kShutdown)->SetVisible(!show_reboot && !is_lock_screen_note_in_foreground); GetViewByID(kRestart)->SetVisible(show_reboot && @@ -628,11 +677,41 @@ kiosk_apps_button_->SetVisible( (!dialog_visible || dialog_state_ == mojom::OobeDialogState::GAIA_SIGNIN) && - kiosk_apps_button_->HasApps() && is_login_primary); + kiosk_apps_button_->HasApps() && (is_login_primary || is_oobe)); + + UpdateButtonColors(is_oobe); Layout(); UpdateButtonUnionBounds(); } +void LoginShelfView::UpdateButtonColors(bool use_dark_colors) { + if (use_dark_colors) { + static_cast<LoginShelfButton*>(GetViewByID(kShutdown))->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kRestart))->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kSignOut))->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kCloseNote))->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kCancel))->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kParentAccess)) + ->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kBrowseAsGuest)) + ->PaintDarkColors(); + static_cast<LoginShelfButton*>(GetViewByID(kAddUser))->PaintDarkColors(); + kiosk_apps_button_->PaintDarkColors(); + } else { + static_cast<LoginShelfButton*>(GetViewByID(kShutdown))->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kRestart))->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kSignOut))->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kCloseNote))->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kCancel))->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kParentAccess)) + ->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kBrowseAsGuest)) + ->PaintLightColors(); + static_cast<LoginShelfButton*>(GetViewByID(kAddUser))->PaintLightColors(); + kiosk_apps_button_->PaintLightColors(); + } +} + void LoginShelfView::UpdateButtonUnionBounds() { button_union_bounds_ = gfx::Rect(); View::Views children = GetChildrenInZOrder();
diff --git a/ash/shelf/login_shelf_view.h b/ash/shelf/login_shelf_view.h index 9daee64..bc6e0906 100644 --- a/ash/shelf/login_shelf_view.h +++ b/ash/shelf/login_shelf_view.h
@@ -5,6 +5,8 @@ #ifndef ASH_SHELF_LOGIN_SHELF_VIEW_H_ #define ASH_SHELF_LOGIN_SHELF_VIEW_H_ +#include <memory> +#include <string> #include <vector> #include "ash/ash_export.h" @@ -61,6 +63,13 @@ kParentAccess // Unlock child device with Parent Access Code. }; + // Stores and notifies UiUpdate test callbacks. + class TestUiUpdateDelegate { + public: + virtual ~TestUiUpdateDelegate(); + virtual void OnUiUpdate() = 0; + }; + explicit LoginShelfView( LockScreenActionBackgroundController* lock_screen_action_background); ~LoginShelfView() override; @@ -101,9 +110,21 @@ // views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; - int ui_update_count() const { return ui_update_count_; } gfx::Rect get_button_union_bounds() const { return button_union_bounds_; } + // Test API. Returns true if request was successful (i.e. button was + // clickable). + bool LaunchAppForTesting(const std::string& app_id); + bool SimulateAddUserButtonForTesting(); + + // Adds test delegate. Delegate will become owned by LoginShelfView. + void InstallTestUiUpdateDelegate( + std::unique_ptr<TestUiUpdateDelegate> delegate); + + TestUiUpdateDelegate* test_ui_update_delegate() { + return test_ui_update_delegate_.get(); + } + protected: // TrayActionObserver: void OnLockScreenNoteStateChanged(mojom::TrayActionState state) override; @@ -129,6 +150,10 @@ // policy updates, session state changes etc. void UpdateUi(); + // Updates the color of all buttons. Uses dark colors if |use_dark_colors| is + // true, light colors otherwise. + void UpdateButtonColors(bool use_dark_colors); + // Updates the total bounds of all buttons. void UpdateButtonUnionBounds(); @@ -157,7 +182,7 @@ KioskAppsButton* kiosk_apps_button_ = nullptr; // Owned by view hierarchy // This is used in tests to wait until UI is updated. - int ui_update_count_ = 0; + std::unique_ptr<TestUiUpdateDelegate> test_ui_update_delegate_; // The bounds of all the buttons that this view is showing. Useful for // letting events that target the "empty space" pass through. These
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 410a5f4..118ea1b 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -11,9 +11,10 @@ #include "ash/animation/animation_change_type.h" #include "ash/app_list/app_list_controller_impl.h" #include "ash/app_list/app_list_metrics.h" -#include "ash/app_list/home_launcher_gesture_handler.h" #include "ash/app_list/model/app_list_view_state.h" #include "ash/app_list/views/app_list_view.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" @@ -181,6 +182,10 @@ Shell::Get()->AddShellObserver(this); Shell::Get()->overview_controller()->AddObserver(this); Shell::Get()->app_list_controller()->AddObserver(this); + Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler() + ->AddObserver(this); Shell::Get()->lock_state_controller()->AddObserver(this); Shell::Get()->activation_client()->AddObserver(this); Shell::Get()->locale_update_controller()->AddObserver(this); @@ -201,8 +206,14 @@ Shell::Get()->locale_update_controller()->RemoveObserver(this); Shell::Get()->RemoveShellObserver(this); Shell::Get()->lock_state_controller()->RemoveObserver(this); - // AppListController is destroyed early when Shell is being destroyed, it may - // not exist. + // The following are destroyed early when Shell is being destroyed so they + // may not exist. + if (Shell::Get()->home_screen_controller()) { + Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler() + ->RemoveObserver(this); + } if (Shell::Get()->app_list_controller()) Shell::Get()->app_list_controller()->RemoveObserver(this); if (Shell::Get()->overview_controller()) @@ -331,9 +342,7 @@ shelf_widget_->GetWindowBoundsInScreen().Contains( display::Screen::GetScreen()->GetCursorScreenPoint()); } - auto_hide_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(kAutoHideDelayMS), this, - &ShelfLayoutManager::UpdateAutoHideStateNow); + StartAutoHideTimer(); } } else { StopAutoHideTimer(); @@ -355,10 +364,22 @@ return; if (event->type() == ui::ET_MOUSE_PRESSED || - (event->type() == ui::ET_MOUSE_MOVED && - GetVisibleShelfBounds().Contains( - display::Screen::GetScreen()->GetCursorScreenPoint()))) { - UpdateAutoHideState(); + event->type() == ui::ET_MOUSE_MOVED) { + if (GetVisibleShelfBounds().Contains( + display::Screen::GetScreen()->GetCursorScreenPoint())) { + UpdateAutoHideState(); + last_seen_mouse_position_was_over_shelf_ = true; + } else { + // The event happened outside the shelf's bounds. If it's a click, hide + // the shelf immediately. If it's a mouse-out, hide after a delay (but + // only if it really is a mouse-out, meaning the mouse actually exited the + // shelf bounds as opposed to having been outside all along). + if (event->type() == ui::ET_MOUSE_PRESSED) + UpdateAutoHideState(); + else if (last_seen_mouse_position_was_over_shelf_) + StartAutoHideTimer(); + last_seen_mouse_position_was_over_shelf_ = false; + } } } @@ -1048,6 +1069,12 @@ StopAutoHideTimer(); } +void ShelfLayoutManager::StartAutoHideTimer() { + auto_hide_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kAutoHideDelayMS), + this, &ShelfLayoutManager::UpdateAutoHideStateNow); +} + void ShelfLayoutManager::StopAutoHideTimer() { auto_hide_timer_.Stop(); mouse_over_shelf_when_auto_hide_timer_started_ = false; @@ -1172,7 +1199,7 @@ gfx::Point cursor_position_in_screen = display::Screen::GetScreen()->GetCursorScreenPoint(); - // Cursor is invisible in talbet mode and plug in an external mouse in tablet + // Cursor is invisible in tablet mode and plug in an external mouse in tablet // mode will switch to clamshell mode. if (shelf_region.Contains(cursor_position_in_screen) && !IsTabletModeEnabled()) { @@ -1296,7 +1323,7 @@ GestureDragStatus previous_drag_status = gesture_drag_status_; gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS; HomeLauncherGestureHandler* home_launcher_handler = - Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); if (home_launcher_handler->OnPressEvent( HomeLauncherGestureHandler::Mode::kSlideUpToShow, gesture_in_screen.location())) { @@ -1327,7 +1354,7 @@ const ui::GestureEvent& gesture_in_screen) { if (ShouldHomeGestureHandleEvent(gesture_in_screen.details().scroll_y())) { HomeLauncherGestureHandler* home_launcher_handler = - Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); if (home_launcher_handler->OnScrollEvent( gesture_in_screen.location(), gesture_in_screen.details().scroll_y())) { @@ -1391,7 +1418,7 @@ return; HomeLauncherGestureHandler* home_launcher_handler = - Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); DCHECK(home_launcher_handler); if (home_launcher_handler->OnReleaseEvent(gesture_in_screen.location())) { gesture_drag_status_ = GESTURE_DRAG_NONE; @@ -1414,7 +1441,7 @@ void ShelfLayoutManager::CancelGestureDrag() { if (gesture_drag_status_ == GESTURE_DRAG_APPLIST_IN_PROGRESS) { HomeLauncherGestureHandler* home_launcher_handler = - Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); DCHECK(home_launcher_handler); if (home_launcher_handler->IsDragInProgress()) home_launcher_handler->Cancel();
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h index 32bfaf4f..e405f28 100644 --- a/ash/shelf/shelf_layout_manager.h +++ b/ash/shelf/shelf_layout_manager.h
@@ -9,6 +9,7 @@ #include "ash/app_list/app_list_controller_observer.h" #include "ash/ash_export.h" +#include "ash/home_screen/home_launcher_gesture_handler_observer.h" #include "ash/public/cpp/shelf_types.h" #include "ash/session/session_observer.h" #include "ash/shelf/shelf.h" @@ -52,6 +53,7 @@ // On mus, widget bounds management is handled by the window manager. class ASH_EXPORT ShelfLayoutManager : public AppListControllerObserver, + public HomeLauncherGestureHandlerObserver, public ShellObserver, public OverviewObserver, public ::wm::ActivationChangeObserver, @@ -153,6 +155,8 @@ // AppListControllerObserver: void OnAppListVisibilityChanged(bool shown, int64_t display_id) override; + + // HomeLauncherGestureHandlerObserver: void OnHomeLauncherTargetPositionChanged(bool showing, int64_t display_id) override; void OnHomeLauncherAnimationComplete(bool shown, int64_t display_id) override; @@ -304,6 +308,10 @@ // Updates the auto hide state immediately. void UpdateAutoHideStateNow(); + // Starts the auto hide timer, so that the shelf will be hidden after the + // timeout (unless something else happens to interrupt / reset it). + void StartAutoHideTimer(); + // Stops the auto hide timer and clears // |mouse_over_shelf_when_auto_hide_timer_started_|. void StopAutoHideTimer(); @@ -407,6 +415,11 @@ // False when neither the auto hide timer nor the timer task are running. bool mouse_over_shelf_when_auto_hide_timer_started_ = false; + // Whether the mouse pointer (not the touch pointer) was over the shelf last + // time we saw it. This is used to differentiate between mouse and touch in + // the shelf autohide behavior. + bool last_seen_mouse_position_was_over_shelf_ = false; + base::ObserverList<ShelfLayoutManagerObserver>::Unchecked observers_; // The shelf reacts to gesture-drags, and can be set to auto-hide for certain
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc index aeeb9e49..f837b99 100644 --- a/ash/shelf/shelf_layout_manager_unittest.cc +++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -9,11 +9,11 @@ #include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_table.h" -#include "ash/app_list/app_list_controller_impl.h" -#include "ash/app_list/home_launcher_gesture_handler.h" #include "ash/app_list/test/app_list_test_helper.h" #include "ash/app_list/views/app_list_view.h" #include "ash/focus_cycler.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" #include "ash/public/cpp/shell_window_ids.h" @@ -438,6 +438,18 @@ return true; } + // Performs a swipe up gesture to show an auto-hidden shelf. + void SwipeUpToShowShelf() { + gfx::Rect display_bounds = + display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); + const gfx::Point start(display_bounds.bottom_center()); + const gfx::Point end(start + gfx::Vector2d(0, -80)); + const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100); + const int kNumScrollSteps = 4; + GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, + kNumScrollSteps); + } + private: base::TimeTicks timestamp_; gfx::Point current_point_; @@ -838,15 +850,7 @@ wm::ActivateWindow(window.get()); if (autohide_shelf) { - gfx::Rect display_bounds = - display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); - const gfx::Point start(display_bounds.bottom_center()); - const gfx::Point end(start + gfx::Vector2d(0, -80)); - const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100); - const int kNumScrollSteps = 4; - // Swipe up to show the auto-hide shelf. - GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, - kNumScrollSteps); + SwipeUpToShowShelf(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); } @@ -867,7 +871,7 @@ // The home launcher gesture handler should not be handling any window // initially. HomeLauncherGestureHandler* gesture_handler = - Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + Shell::Get()->home_screen_controller()->home_launcher_gesture_handler(); ASSERT_TRUE(gesture_handler); ASSERT_FALSE(gesture_handler->GetWindow1()); @@ -2586,6 +2590,51 @@ } } +// Tests the auto-hide shelf status when moving the mouse in and out. +TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnMouseMove) { + // Create one window, or the shelf won't auto-hide. + CreateTestWidget(); + Shelf* shelf = GetPrimaryShelf(); + ui::test::EventGenerator* generator = GetEventGenerator(); + display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); + + // Set the shelf to auto-hide. + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + ShelfLayoutManager* layout_manager = GetShelfLayoutManager(); + layout_manager->LayoutShelf(); + EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); + + // Swipe up to show the shelf. + SwipeUpToShowShelf(); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); + + // Move the mouse far away from the shelf, but without having been on the + // shelf first. This isn't technically a mouse-out event, so the shelf should + // not hide. + generator->MoveMouseTo(0, 0); + ASSERT_FALSE(TriggerAutoHideTimeout()); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); + + // Now place the mouse on the shelf, then move away. The shelf should hide. + generator->MoveMouseTo(1, display.bounds().bottom() - 1); + generator->MoveMouseTo(0, 0); + ASSERT_TRUE(TriggerAutoHideTimeout()); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); + + // Now let's show the shelf again. + SwipeUpToShowShelf(); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); + + // Move the mouse away, but move it back within the shelf immediately. The + // shelf should remain shown. + generator->MoveMouseTo(0, 0); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); + generator->MoveMouseTo(1, display.bounds().bottom() - 1); + ASSERT_FALSE(TriggerAutoHideTimeout()); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); +} + // Tests the auto-hide shelf status with mouse events. TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnMouseEvents) { views::Widget* widget = CreateTestWidget(); @@ -2600,17 +2649,11 @@ EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); - gfx::Rect display_bounds = - display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); - const gfx::Point start(display_bounds.bottom_center()); - const gfx::Point end(start + gfx::Vector2d(0, -80)); - const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100); - const int kNumScrollSteps = 4; // Swipe up to show the auto-hide shelf. - generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps); + SwipeUpToShowShelf(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); - // Move the mouse should not hide the AUTO_HIDE_SHOWN shelf. + // Move the mouse should not hide the AUTO_HIDE_SHOWN shelf immediately. generator->MoveMouseTo(5, 5); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index cb893301..bae639d4 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -528,6 +528,20 @@ // * when views based shelf is disabled // * in UNKNOWN state - it might be called before shelf was initialized // * on secondary screens in states other than ACTIVE + // + // TODO(alemate): better handle show-hide for some UI screens: + // https://crbug.com/935842 + // https://crbug.com/935844 + // https://crbug.com/935846 + // https://crbug.com/935847 + // https://crbug.com/935852 + // https://crbug.com/935853 + // https://crbug.com/935856 + // https://crbug.com/935857 + // https://crbug.com/935858 + // https://crbug.com/935860 + // https://crbug.com/935861 + // https://crbug.com/935863 bool using_views_shelf = IsUsingViewsShelf(); bool unknown_state = state == session_manager::SessionState::UNKNOWN; bool hide_on_secondary_screen = shelf_->ShouldHideOnSecondaryDisplay(state);
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc index dbf0413..964e3c54 100644 --- a/ash/shelf/shelf_window_watcher.cc +++ b/ash/shelf/shelf_window_watcher.cc
@@ -65,7 +65,9 @@ } // Prefer app icons over window icons, they're typically larger. - gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey); + gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconLargeKey); + if (!image || image->isNull()) + image = window->GetProperty(aura::client::kAppIconKey); if (!image || image->isNull()) image = window->GetProperty(aura::client::kWindowIconKey); if (!image || image->isNull()) {
diff --git a/ash/shell.cc b/ash/shell.cc index 0c5710b..1eee4d16 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -54,6 +54,7 @@ #include "ash/frame/non_client_frame_view_ash.h" #include "ash/high_contrast/high_contrast_controller.h" #include "ash/highlighter/highlighter_controller.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/host/ash_window_tree_host_init_params.h" #include "ash/ime/ime_controller.h" #include "ash/ime/ime_focus_handler.h" @@ -748,7 +749,11 @@ // Depends on |tablet_mode_controller_|. shelf_controller_->Shutdown(); - // Destroy |app_list_controller_| early than |tablet_mode_controller_| since + // Destroy |home_screen_controller_| before |app_list_controller_| since + // the former delegates to the latter. + home_screen_controller_.reset(); + + // Destroy |app_list_controller_| earlier than |tablet_mode_controller_| since // the former may use the latter before destruction. app_list_controller_.reset(); @@ -1165,17 +1170,16 @@ magnification_controller_ = std::make_unique<MagnificationController>(); mru_window_tracker_ = std::make_unique<MruWindowTracker>(); - - // |assistant_controller_| needs to be created before |app_list_controller_| - // since it is used by the latter in constructor. assistant_controller_ = chromeos::switches::IsAssistantEnabled() ? std::make_unique<AssistantController>() : nullptr; + home_screen_controller_ = std::make_unique<HomeScreenController>(); - // |tablet_mode_controller_| |mru_window_tracker_|, and - // |assistant_controller_| are put before |app_list_controller_| as they are - // used in constructor. + // |tablet_mode_controller_| |mru_window_tracker_|, + // |assistant_controller_| and |home_screen_controller_| are put before + // |app_list_controller_| as they are used in its constructor. app_list_controller_ = std::make_unique<AppListControllerImpl>(); + home_screen_controller_->SetDelegate(app_list_controller_.get()); autoclick_controller_ = std::make_unique<AutoclickController>();
diff --git a/ash/shell.h b/ash/shell.h index 8a2f8cf..678c69d 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -128,6 +128,7 @@ class FocusCycler; class HighContrastController; class HighlighterController; +class HomeScreenController; class ImeController; class ImeFocusHandler; class ImmersiveContext; @@ -406,6 +407,9 @@ EventTransformationHandler* event_transformation_handler() { return event_transformation_handler_.get(); } + HomeScreenController* home_screen_controller() { + return home_screen_controller_.get(); + } FirstRunHelper* first_run_helper() { return first_run_helper_.get(); } ::wm::FocusController* focus_controller() { return focus_controller_.get(); } ::wm::FocusRules* focus_rules() { return focus_rules_; } @@ -729,6 +733,7 @@ std::unique_ptr<DragDropController> drag_drop_controller_; std::unique_ptr<FirstRunHelper> first_run_helper_; std::unique_ptr<FocusCycler> focus_cycler_; + std::unique_ptr<HomeScreenController> home_screen_controller_; std::unique_ptr<ImeController> ime_controller_; std::unique_ptr<ImeFocusHandler> ime_focus_handler_; std::unique_ptr<ImmersiveContext> immersive_context_;
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index ccaead4..113ce77 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc
@@ -39,6 +39,8 @@ #include "components/account_id/account_id.h" #include "components/user_manager/user_names.h" #include "mojo/public/cpp/bindings/map.h" +#include "services/ws/public/cpp/input_devices/input_device_client.h" +#include "services/ws/public/cpp/input_devices/input_device_client_test_api.h" #include "services/ws/public/cpp/property_type_converters.h" #include "services/ws/public/mojom/window_manager.mojom.h" #include "services/ws/public/mojom/window_tree_constants.mojom.h" @@ -187,6 +189,10 @@ // Some tests set an internal display id, // reset it here, so other tests will continue in a clean environment. display::Display::SetInternalDisplayId(display::kInvalidDisplayId); + + // Tests can add devices, so reset the lists for future tests. + ws::InputDeviceClientTestApi().SetTouchscreenDevices({}); + ws::InputDeviceClientTestApi().SetKeyboardDevices({}); } // static
diff --git a/ash/wm/overview/caption_container_view.cc b/ash/wm/overview/caption_container_view.cc index fed7332..9c67eb8 100644 --- a/ash/wm/overview/caption_container_view.cc +++ b/ash/wm/overview/caption_container_view.cc
@@ -243,7 +243,11 @@ kHorizontalLabelPaddingDp)); AddChildWithLayer(listener_button_, header_view_); - gfx::ImageSkia* icon = window->GetProperty(aura::client::kAppIconKey); + // Prefer kAppIconSmallKey (set by the client in Mash), then kAppIconKey and + // kWindowIconKey (set for client windows in classic Ash but not Mash). + gfx::ImageSkia* icon = window->GetProperty(aura::client::kAppIconSmallKey); + if (!icon || icon->size().IsEmpty()) + icon = window->GetProperty(aura::client::kAppIconKey); if (!icon || icon->size().IsEmpty()) icon = window->GetProperty(aura::client::kWindowIconKey); if (icon && !icon->size().IsEmpty()) {
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index 8d688ab..da5f3af 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -6,8 +6,8 @@ #include <utility> -#include "ash/app_list/app_list_controller_impl.h" -#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" @@ -295,7 +295,7 @@ return false; if (Shell::Get() - ->app_list_controller() + ->home_screen_controller() ->home_launcher_gesture_handler() ->mode() == HomeLauncherGestureHandler::Mode::kSlideUpToShow) { return true;
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc index 8ddaa2f..115c838f 100644 --- a/ash/wm/splitview/split_view_utils.cc +++ b/ash/wm/splitview/split_view_utils.cc
@@ -73,14 +73,16 @@ *out_tween_type = gfx::Tween::LINEAR_OUT_SLOW_IN; return; case SPLITVIEW_ANIMATION_TEXT_FADE_IN: - case SPLITVIEW_ANIMATION_TEXT_FADE_OUT: case SPLITVIEW_ANIMATION_TEXT_SLIDE_IN: - case SPLITVIEW_ANIMATION_TEXT_SLIDE_OUT: - if (type == SPLITVIEW_ANIMATION_TEXT_SLIDE_IN) - *out_delay = kLabelAnimationDelayMs; + *out_delay = kLabelAnimationDelayMs; *out_duration = kLabelAnimationMs; *out_tween_type = gfx::Tween::LINEAR_OUT_SLOW_IN; return; + case SPLITVIEW_ANIMATION_TEXT_FADE_OUT: + case SPLITVIEW_ANIMATION_TEXT_SLIDE_OUT: + *out_duration = kLabelAnimationMs; + *out_tween_type = gfx::Tween::FAST_OUT_LINEAR_IN; + return; case SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_OUT: case SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_SLIDE_OUT: *out_delay = kOtherFadeOutDelayMs;
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index ba01102..ee66b65d 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc
@@ -10,8 +10,8 @@ #include <utility> #include <vector> -#include "ash/app_list/app_list_controller_impl.h" -#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/window_animation_types.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" @@ -246,17 +246,17 @@ } bool AnimateShowWindow_SlideDown(aura::Window* window) { - AppListControllerImpl* app_list_controller = - Shell::Get()->app_list_controller(); + HomeScreenController* home_screen_controller = + Shell::Get()->home_screen_controller(); const TabletModeController* tablet_mode_controller = Shell::Get()->tablet_mode_controller(); - if (app_list_controller && tablet_mode_controller && + if (home_screen_controller && tablet_mode_controller && tablet_mode_controller->IsTabletModeWindowManagerEnabled()) { // Slide down the window from above screen to show and, meanwhile, slide // down the home launcher off screen. HomeLauncherGestureHandler* handler = - app_list_controller->home_launcher_gesture_handler(); + home_screen_controller->home_launcher_gesture_handler(); if (handler && handler->HideHomeLauncherForWindow( display::Screen::GetScreen()->GetDisplayNearestView(window),
diff --git a/base/android/child_process_service.cc b/base/android/child_process_service.cc index 93c03d41..9297b98 100644 --- a/base/android/child_process_service.cc +++ b/base/android/child_process_service.cc
@@ -5,6 +5,7 @@ #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/library_loader/library_loader_hooks.h" +#include "base/debug/dump_without_crashing.h" #include "base/file_descriptor_store.h" #include "base/logging.h" #include "base/macros.h" @@ -72,5 +73,9 @@ _exit(0); } +void JNI_ChildProcessService_DumpProcessStack(JNIEnv* env) { + base::debug::DumpWithoutCrashing(); +} + } // namespace android } // namespace base
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java index eef08c4..fe89894 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -437,6 +437,19 @@ notifyChildProcessDied(); } + /** + * Dumps the stack of the child process without crashing it. + */ + public void dumpProcessStack() { + assert isRunningOnLauncherThread(); + IChildProcessService service = mService; + try { + if (service != null) service.dumpProcessStack(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to dump process stack.", e); + } + } + @VisibleForTesting protected void onServiceConnectedOnLauncherThread(IBinder service) { assert isRunningOnLauncherThread();
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java index 2364197c..6a5aaa8 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java
@@ -187,6 +187,19 @@ } }); } + + @Override + public void dumpProcessStack() { + assert mServiceBound; + synchronized (mLibraryInitializedLock) { + if (!mLibraryInitialized) { + Log.e(TAG, "Cannot dump process stack before native is loaded"); + return; + } + } + nativeDumpProcessStack(); + } + }; /** @@ -361,4 +374,9 @@ * Force the child process to exit. */ private static native void nativeExitChildProcess(); + + /** + * Dumps the child process stack without crashing it. + */ + private static native void nativeDumpProcessStack(); }
diff --git a/base/android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl b/base/android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl index bca9c171..78e1baf3 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl +++ b/base/android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl
@@ -23,4 +23,7 @@ // Notifies about memory pressure. The argument is MemoryPressureLevel enum. oneway void onMemoryPressure(int pressure); + + // Dumps the stack for the child process without crashing it. + oneway void dumpProcessStack(); }
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc index 0a32704..29e2f434 100644 --- a/base/profiler/native_stack_sampler_win.cc +++ b/base/profiler/native_stack_sampler_win.cc
@@ -188,31 +188,21 @@ #endif } -// Movable type representing a recorded stack frame. +// Represents a recorded stack frame. struct RecordedFrame { - RecordedFrame() {} - - RecordedFrame(RecordedFrame&& other) - : instruction_pointer(other.instruction_pointer), - module(std::move(other.module)) {} - - RecordedFrame& operator=(RecordedFrame&& other) { - instruction_pointer = other.instruction_pointer; - module = std::move(other.module); - return *this; - } + RecordedFrame(const void* instruction_pointer, + const ModuleCache::Module* module) + : instruction_pointer(instruction_pointer), module(module) {} const void* instruction_pointer; - ScopedModuleHandle module; - - private: - DISALLOW_COPY_AND_ASSIGN(RecordedFrame); + const ModuleCache::Module* module; }; // Walks the stack represented by |context| from the current frame downwards, // recording the instruction pointer and associated module for each frame in // |stack|. -NativeStackSamplerError RecordStack(CONTEXT* context, +NativeStackSamplerError RecordStack(ModuleCache* module_cache, + CONTEXT* context, std::vector<RecordedFrame>* stack) { #ifdef _WIN64 DCHECK(stack->empty()); @@ -222,17 +212,14 @@ // fewer. stack->reserve(128); - Win32StackFrameUnwinder frame_unwinder; + Win32StackFrameUnwinder frame_unwinder(module_cache); while (ContextPC(context)) { const void* instruction_pointer = reinterpret_cast<const void*>(ContextPC(context)); - ScopedModuleHandle module; + const ModuleCache::Module* module = nullptr; if (!frame_unwinder.TryUnwind(context, &module)) return NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED; - RecordedFrame frame; - frame.instruction_pointer = instruction_pointer; - frame.module = std::move(module); - stack->push_back(std::move(frame)); + stack->emplace_back(instruction_pointer, module); } return NATIVE_STACK_SAMPLER_SUCCESS; #else @@ -341,6 +328,7 @@ const void* base_address, void* stack_copy_buffer, size_t stack_copy_buffer_size, + ModuleCache* module_cache, std::vector<RecordedFrame>* stack, ProfileBuilder* profile_builder, NativeStackSamplerTestDelegate* test_delegate) { @@ -400,7 +388,7 @@ RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); - return RecordStack(&thread_context, stack); + return RecordStack(module_cache, &thread_context, stack); } } @@ -460,7 +448,8 @@ std::vector<RecordedFrame> stack; NativeStackSamplerError error_code = SuspendThreadAndRecordStack( thread_handle_.Get(), thread_stack_base_address_, stack_buffer->buffer(), - stack_buffer->size(), &stack, profile_builder, test_delegate_); + stack_buffer->size(), module_cache_, &stack, profile_builder, + test_delegate_); if (error_code != NATIVE_STACK_SAMPLER_SUCCESS) { TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), @@ -483,7 +472,7 @@ for (const auto& frame : stack) { frames.emplace_back(reinterpret_cast<uintptr_t>(frame.instruction_pointer), - module_cache_->GetModuleForHandle(frame.module.Get())); + frame.module); } return frames;
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc index 204b3983..cfbcbd2 100644 --- a/base/profiler/win32_stack_frame_unwinder.cc +++ b/base/profiler/win32_stack_frame_unwinder.cc
@@ -15,34 +15,13 @@ // Win32UnwindFunctions ------------------------------------------------------- -const HMODULE ModuleHandleTraits::kNonNullModuleForTesting = - reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1)); - -// static -bool ModuleHandleTraits::CloseHandle(HMODULE handle) { - if (handle == kNonNullModuleForTesting) - return true; - - return ::FreeLibrary(handle) != 0; -} - -// static -bool ModuleHandleTraits::IsHandleValid(HMODULE handle) { - return handle != nullptr; -} - -// static -HMODULE ModuleHandleTraits::NullHandle() { - return nullptr; -} - namespace { // Implements the UnwindFunctions interface for the corresponding Win32 // functions. class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { -public: - Win32UnwindFunctions(); + public: + explicit Win32UnwindFunctions(ModuleCache* module_cache); ~Win32UnwindFunctions() override; PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, @@ -53,14 +32,17 @@ PRUNTIME_FUNCTION runtime_function, CONTEXT* context) override; - ScopedModuleHandle GetModuleForProgramCounter( + const ModuleCache::Module* GetModuleForProgramCounter( DWORD64 program_counter) override; -private: + private: + ModuleCache* module_cache_; + DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions); }; -Win32UnwindFunctions::Win32UnwindFunctions() {} +Win32UnwindFunctions::Win32UnwindFunctions(ModuleCache* module_cache) + : module_cache_(module_cache) {} Win32UnwindFunctions::~Win32UnwindFunctions() {} PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry( @@ -90,18 +72,9 @@ #endif } -ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter( +const ModuleCache::Module* Win32UnwindFunctions::GetModuleForProgramCounter( DWORD64 program_counter) { - HMODULE module_handle = nullptr; - // GetModuleHandleEx() increments the module reference count, which is then - // managed and ultimately decremented by ScopedModuleHandle. - if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast<LPCTSTR>(program_counter), - &module_handle)) { - const DWORD error = ::GetLastError(); - DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error)); - } - return ScopedModuleHandle(module_handle); + return module_cache_->GetModuleForAddress(program_counter); } } // namespace @@ -111,19 +84,20 @@ Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} -Win32StackFrameUnwinder::Win32StackFrameUnwinder() - : Win32StackFrameUnwinder(std::make_unique<Win32UnwindFunctions>()) {} +Win32StackFrameUnwinder::Win32StackFrameUnwinder(ModuleCache* module_cache) + : Win32StackFrameUnwinder( + std::make_unique<Win32UnwindFunctions>(module_cache)) {} Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, - ScopedModuleHandle* module) { + const ModuleCache::Module** module) { #ifdef _WIN64 - // TODO(wittman): update base::ModuleCache to return a ScopedModuleHandle and - // use it for this module lookup. - ScopedModuleHandle frame_module = + *module = nullptr; + + const ModuleCache::Module* frame_module = unwind_functions_->GetModuleForProgramCounter(ContextPC(context)); - if (!frame_module.IsValid()) { + if (!frame_module) { // There's no loaded module containing the instruction pointer. This can be // due to executing code that is not in a module. In particular, // runtime-generated code associated with third-party injected DLLs @@ -184,7 +158,7 @@ } } - module->Set(frame_module.Take()); + *module = frame_module; return true; #else NOTREACHED();
diff --git a/base/profiler/win32_stack_frame_unwinder.h b/base/profiler/win32_stack_frame_unwinder.h index 144cc6e..0d1da36 100644 --- a/base/profiler/win32_stack_frame_unwinder.h +++ b/base/profiler/win32_stack_frame_unwinder.h
@@ -11,7 +11,7 @@ #include "base/base_export.h" #include "base/macros.h" -#include "base/win/scoped_handle.h" +#include "base/sampling_heap_profiler/module_cache.h" #include "build/build_config.h" namespace base { @@ -38,26 +38,6 @@ } #endif -// Traits class to adapt GenericScopedHandle for HMODULES. -class ModuleHandleTraits : public win::HandleTraits { - public: - using Handle = HMODULE; - - static bool BASE_EXPORT CloseHandle(HMODULE handle); - static bool BASE_EXPORT IsHandleValid(HMODULE handle); - static HMODULE BASE_EXPORT NullHandle(); - - BASE_EXPORT static const HMODULE kNonNullModuleForTesting; - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits); -}; - -// HMODULE is not really a handle, and has reference count semantics, so the -// standard VerifierTraits does not apply. -using ScopedModuleHandle = - win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>; - // Instances of this class are expected to be created and destroyed for each // stack unwinding. This class is not used while the target thread is suspended, // so may allocate from the default heap. @@ -78,7 +58,7 @@ // Returns the module containing |program_counter|. Can return null if the // module has been unloaded. - virtual ScopedModuleHandle GetModuleForProgramCounter( + virtual const ModuleCache::Module* GetModuleForProgramCounter( DWORD64 program_counter) = 0; protected: @@ -88,13 +68,13 @@ DISALLOW_COPY_AND_ASSIGN(UnwindFunctions); }; - Win32StackFrameUnwinder(); + explicit Win32StackFrameUnwinder(ModuleCache* module_cache); ~Win32StackFrameUnwinder(); // Attempts to unwind the frame represented by the stack and instruction // pointers in |context|. If successful, updates |context| and provides the - // module associated with the frame in |module|. - bool TryUnwind(CONTEXT* context, ScopedModuleHandle* module); + // module associated with the frame in *|module|. + bool TryUnwind(CONTEXT* context, const ModuleCache::Module** module); private: // This function is for internal and test purposes only.
diff --git a/base/profiler/win32_stack_frame_unwinder_unittest.cc b/base/profiler/win32_stack_frame_unwinder_unittest.cc index cecfe22..bc6d986 100644 --- a/base/profiler/win32_stack_frame_unwinder_unittest.cc +++ b/base/profiler/win32_stack_frame_unwinder_unittest.cc
@@ -17,6 +17,17 @@ namespace { +// Stub module for testing. +class TestModule : public ModuleCache::Module { + public: + uintptr_t GetBaseAddress() const override { return 0; } + std::string GetId() const override { return ""; } + FilePath GetDebugBasename() const override { return FilePath(); } + size_t GetSize() const override { return 0; } +}; + +const TestModule valid_module; + class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { public: TestUnwindFunctions(); @@ -27,7 +38,7 @@ DWORD64 program_counter, PRUNTIME_FUNCTION runtime_function, CONTEXT* context) override; - ScopedModuleHandle GetModuleForProgramCounter( + const ModuleCache::Module* GetModuleForProgramCounter( DWORD64 program_counter) override; // Instructs GetModuleForProgramCounter to return null on the next call. @@ -90,13 +101,11 @@ EXPECT_EQ(&runtime_functions_.back(), runtime_function); } -ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter( +const ModuleCache::Module* TestUnwindFunctions::GetModuleForProgramCounter( DWORD64 program_counter) { bool return_non_null_value = module_is_loaded_; module_is_loaded_ = true; - return ScopedModuleHandle(return_non_null_value ? - ModuleHandleTraits::kNonNullModuleForTesting : - nullptr); + return return_non_null_value ? &valid_module : nullptr; } void TestUnwindFunctions::SetUnloadedModule() { @@ -149,28 +158,28 @@ TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); CONTEXT context = {0}; - ScopedModuleHandle module; + const ModuleCache::Module* module = nullptr; unwind_functions_->SetHasRuntimeFunction(&context); EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); + module = nullptr; EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); + module = nullptr; EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); } // Checks that an instruction pointer in an unloaded module fails to unwind. TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); CONTEXT context = {0}; - ScopedModuleHandle module; + const ModuleCache::Module* module = nullptr; unwind_functions_->SetUnloadedModule(); EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); @@ -181,7 +190,7 @@ TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); CONTEXT context = {0}; - ScopedModuleHandle module; + const ModuleCache::Module* module = nullptr; DWORD64 next_ip = 0x0123456789abcdef; DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip); context.Rsp = original_rsp; @@ -190,17 +199,17 @@ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); EXPECT_EQ(next_ip, context.Rip); EXPECT_EQ(original_rsp + 8, context.Rsp); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); + module = nullptr; EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); unwind_functions_->SetHasRuntimeFunction(&context); - module.Set(nullptr); + module = nullptr; EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); } // Checks that a frame below the top of the stack with missing unwind info @@ -210,10 +219,10 @@ // First stack, with a bad function below the top of the stack. std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); CONTEXT context = {0}; - ScopedModuleHandle module; + const ModuleCache::Module* module = nullptr; unwind_functions_->SetHasRuntimeFunction(&context); EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); - EXPECT_TRUE(module.IsValid()); + EXPECT_NE(nullptr, module); unwind_functions_->SetNoRuntimeFunction(&context); EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
diff --git a/base/sampling_heap_profiler/module_cache.h b/base/sampling_heap_profiler/module_cache.h index 2b5189b..45cee33 100644 --- a/base/sampling_heap_profiler/module_cache.h +++ b/base/sampling_heap_profiler/module_cache.h
@@ -20,6 +20,16 @@ namespace base { +// Supports cached lookup of modules by address, with caching based on module +// address ranges. +// +// Cached lookup is necessary on Mac for performance, due to an inefficient +// dladdr implementation. See https://crrev.com/487092. +// +// Cached lookup is beneficial on Windows to minimize use of the loader +// lock. Note however that the cache retains a handle to looked-up modules for +// its lifetime, which may result in pinning modules in memory that were +// transiently loaded by the OS. class BASE_EXPORT ModuleCache { public: // Module represents a binary module (executable or library) and its @@ -77,16 +87,6 @@ friend bool MayTriggerUnwInitLocalCrash(uint64_t); #endif -#if defined(OS_WIN) - const Module* GetModuleForHandle(HMODULE module_handle); - static std::unique_ptr<Module> CreateModuleForHandle(HMODULE module_handle); - friend class NativeStackSamplerWin; - - // The module objects, indexed by the module handle. - // TODO(wittman): Merge this state into modules_cache_map_ and remove - std::map<HMODULE, std::unique_ptr<Module>> win_module_cache_; -#endif - std::map<uintptr_t, std::unique_ptr<Module>> modules_cache_map_; };
diff --git a/base/sampling_heap_profiler/module_cache_win.cc b/base/sampling_heap_profiler/module_cache_win.cc index a192054..9cc2374 100644 --- a/base/sampling_heap_profiler/module_cache_win.cc +++ b/base/sampling_heap_profiler/module_cache_win.cc
@@ -63,85 +63,92 @@ *build_id = UTF16ToUTF8(buffer); } -} // namespace +// Traits class to adapt GenericScopedHandle for HMODULES. +class ModuleHandleTraits : public win::HandleTraits { + public: + using Handle = HMODULE; + + static bool CloseHandle(HMODULE handle) { return ::FreeLibrary(handle) != 0; } + static bool IsHandleValid(HMODULE handle) { return handle != nullptr; } + static HMODULE NullHandle() { return nullptr; } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits); +}; + +// HMODULE is not really a handle, and has reference count semantics, so the +// standard VerifierTraits does not apply. +using ScopedModuleHandle = + win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>; class WindowsModule : public ModuleCache::Module { public: - WindowsModule(uintptr_t base_address, + WindowsModule(ScopedModuleHandle module_handle, + const MODULEINFO module_info, const std::string& id, - const FilePath& debug_basename, - size_t size) - : base_address_(base_address), + const FilePath& debug_basename) + : module_handle_(std::move(module_handle)), + module_info_(module_info), id_(id), - debug_basename_(debug_basename), - size_(size) {} + debug_basename_(debug_basename) {} WindowsModule(const WindowsModule&) = delete; WindowsModule& operator=(const WindowsModule&) = delete; // ModuleCache::Module - uintptr_t GetBaseAddress() const override { return base_address_; } + uintptr_t GetBaseAddress() const override { + return reinterpret_cast<uintptr_t>(module_info_.lpBaseOfDll); + } + std::string GetId() const override { return id_; } FilePath GetDebugBasename() const override { return debug_basename_; } - size_t GetSize() const override { return size_; } + size_t GetSize() const override { return module_info_.SizeOfImage; } private: - uintptr_t base_address_; + ScopedModuleHandle module_handle_; + const MODULEINFO module_info_; std::string id_; FilePath debug_basename_; - size_t size_; }; -// static -std::unique_ptr<ModuleCache::Module> ModuleCache::CreateModuleForAddress( - uintptr_t address) { +ScopedModuleHandle GetModuleHandleForAddress(DWORD64 address) { HMODULE module_handle = nullptr; + // GetModuleHandleEx() increments the module reference count, which is then + // managed and ultimately decremented by ScopedModuleHandle. if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCTSTR>(address), &module_handle)) { - DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(::GetLastError())); - return nullptr; + const DWORD error = ::GetLastError(); + DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error)); } - std::unique_ptr<Module> module = CreateModuleForHandle(module_handle); - ::CloseHandle(module_handle); - return module; + return ScopedModuleHandle(module_handle); } -const ModuleCache::Module* ModuleCache::GetModuleForHandle( - HMODULE module_handle) { - if (!module_handle) - return nullptr; - - auto loc = win_module_cache_.find(module_handle); - if (loc != win_module_cache_.end()) - return loc->second.get(); - - std::unique_ptr<ModuleCache::Module> module = - ModuleCache::CreateModuleForHandle(module_handle); - if (!module) - return nullptr; - - const auto result = win_module_cache_.insert( - std::make_pair(module_handle, std::move(module))); - return result.first->second.get(); -} - -// static -std::unique_ptr<ModuleCache::Module> ModuleCache::CreateModuleForHandle( - HMODULE module_handle) { +std::unique_ptr<ModuleCache::Module> CreateModuleForHandle( + ScopedModuleHandle module_handle) { FilePath pdb_name; std::string build_id; - GetDebugInfoForModule(module_handle, &build_id, &pdb_name); + GetDebugInfoForModule(module_handle.Get(), &build_id, &pdb_name); MODULEINFO module_info; - if (!::GetModuleInformation(GetCurrentProcessHandle(), module_handle, + if (!::GetModuleInformation(GetCurrentProcessHandle(), module_handle.Get(), &module_info, sizeof(module_info))) { return nullptr; } - return std::make_unique<WindowsModule>( - reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), build_id, pdb_name, - module_info.SizeOfImage); + return std::make_unique<WindowsModule>(std::move(module_handle), module_info, + build_id, pdb_name); +} + +} // namespace + +// static +std::unique_ptr<ModuleCache::Module> ModuleCache::CreateModuleForAddress( + uintptr_t address) { + ScopedModuleHandle module_handle = GetModuleHandleForAddress(address); + if (!module_handle.IsValid()) + return nullptr; + return CreateModuleForHandle(std::move(module_handle)); } } // namespace base
diff --git a/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java b/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java index ffbc213..b1104b3 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java +++ b/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java
@@ -14,6 +14,9 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CallbackHelper; +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.TimeoutException; /** @@ -22,6 +25,21 @@ */ public class DestroyActivitiesRule extends ExternalResource { private static final String TAG = "DestroyActivities"; + private final Set<Activity> mBlacklistedActivities = + Collections.newSetFromMap(new WeakHashMap<>()); + + private boolean allActivitiesDestroyedOrBlacklisted() { + if (ApplicationStatus.isEveryActivityDestroyed()) { + return true; + } + for (Activity a : ApplicationStatus.getRunningActivities()) { + if (!mBlacklistedActivities.contains(a)) { + return false; + } + } + return true; + } + @Override public void after() { if (!ApplicationStatus.isInitialized()) { @@ -34,7 +52,7 @@ public void onActivityStateChange(Activity activity, int newState) { switch (newState) { case ActivityState.DESTROYED: - if (ApplicationStatus.isEveryActivityDestroyed()) { + if (allActivitiesDestroyedOrBlacklisted()) { allDestroyedCalledback.notifyCalled(); ApplicationStatus.unregisterActivityStateListener(this); } @@ -51,13 +69,13 @@ }; ThreadUtils.runOnUiThread(() -> { - if (ApplicationStatus.isEveryActivityDestroyed()) { + if (allActivitiesDestroyedOrBlacklisted()) { allDestroyedCalledback.notifyCalled(); } else { ApplicationStatus.registerStateListenerForAllActivities(activityStateListener); } for (Activity a : ApplicationStatus.getRunningActivities()) { - if (!a.isFinishing()) { + if (!a.isFinishing() && !mBlacklistedActivities.contains(a)) { a.finish(); } } @@ -70,9 +88,8 @@ Log.w(TAG, "Activity failed to be destroyed after a test"); ThreadUtils.runOnUiThreadBlocking(() -> { - for (Activity a : ApplicationStatus.getRunningActivities()) { - ApplicationStatus.onStateChangeForTesting(a, ActivityState.DESTROYED); - } + mBlacklistedActivities.addAll(ApplicationStatus.getRunningActivities()); + // Make sure subsequent tests don't have these notifications firing. ApplicationStatus.unregisterActivityStateListener(activityStateListener); });
diff --git a/build/android/gyp/create_stub_manifest.py b/build/android/gyp/create_stub_manifest.py deleted file mode 100755 index ecaca9d..0000000 --- a/build/android/gyp/create_stub_manifest.py +++ /dev/null
@@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2019 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. - -"""Generates a manifest with reference attributes removed.""" - -import argparse -import re - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - '--input', required=True, help='Path to the input manifest.') - parser.add_argument( - '--output', required=True, help='Path to the output manifest.') - args = parser.parse_args() - - with open(args.input) as manifest_file: - stub_manifest = manifest_file.read() - - stub_manifest = re.sub( - r'<meta-data[^>]*android:resource[^>]*/>', - '', - stub_manifest, - flags=re.MULTILINE) - stub_manifest = re.sub(r'android:[^=]*=\s*"@[^"]+"', '', stub_manifest) - - with open(args.output, 'w') as out_file: - out_file.write(stub_manifest) - - -if __name__ == '__main__': - main()
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py index e7374410..2d493f7 100755 --- a/build/android/gyp/java_cpp_enum.py +++ b/build/android/gyp/java_cpp_enum.py
@@ -15,6 +15,7 @@ import zipfile from util import build_utils +from util import java_cpp_utils # List of C++ types that are compatible with the Java code generated by this # script. @@ -115,8 +116,8 @@ self.comments = StripEntries(self.comments) def _NormalizeNames(self): - self.entries = _TransformKeys(self.entries, _KCamelToShouty) - self.comments = _TransformKeys(self.comments, _KCamelToShouty) + self.entries = _TransformKeys(self.entries, java_cpp_utils.KCamelToShouty) + self.comments = _TransformKeys(self.comments, java_cpp_utils.KCamelToShouty) def _TransformKeys(d, func): @@ -133,25 +134,6 @@ return ret -def _KCamelToShouty(s): - """Convert |s| from kCamelCase or CamelCase to SHOUTY_CASE. - - kFooBar -> FOO_BAR - FooBar -> FOO_BAR - FooBAR9 -> FOO_BAR9 - FooBARBaz -> FOO_BAR_BAZ - """ - if not re.match(r'^k?([A-Z][^A-Z]+|[A-Z0-9]+)+$', s): - return s - # Strip the leading k. - s = re.sub(r'^k', '', s) - # Add _ between title words and anything else. - s = re.sub(r'([^_])([A-Z][^A-Z_0-9]+)', r'\1_\2', s) - # Add _ between lower -> upper transitions. - s = re.sub(r'([^A-Z_0-9])([A-Z])', r'\1_\2', s) - return s.upper() - - class DirectiveSet(object): class_name_override_key = 'CLASS_NAME_OVERRIDE' enum_package_key = 'ENUM_PACKAGE' @@ -334,8 +316,6 @@ if single_line_enum: self._ParseSingleLineEnum(single_line_enum.group('enum_entries')) -def GetScriptName(): - return os.path.basename(os.path.abspath(sys.argv[0])) def DoGenerate(source_paths): for source_path in source_paths: @@ -395,15 +375,15 @@ } enum_comments = enum_definition.comments.get(enum_name) if enum_comments: - enum_comments_indent = ' * ' - comments_line_wrapper = textwrap.TextWrapper( - initial_indent=enum_comments_indent, - subsequent_indent=enum_comments_indent, - width=100) - enum_entries_string.append(' /**') - enum_entries_string.append( - '\n'.join(comments_line_wrapper.wrap(enum_comments))) - enum_entries_string.append(' */') + enum_comments_indent = ' * ' + comments_line_wrapper = textwrap.TextWrapper( + initial_indent=enum_comments_indent, + subsequent_indent=enum_comments_indent, + width=100) + enum_entries_string.append(' /**') + enum_entries_string.append('\n'.join( + comments_line_wrapper.wrap(enum_comments))) + enum_entries_string.append(' */') enum_entries_string.append(enum_template.substitute(values)) enum_names.append(enum_definition.class_name + '.' + enum_name) enum_entries_string = '\n'.join(enum_entries_string) @@ -419,7 +399,7 @@ 'ENUM_ENTRIES': enum_entries_string, 'PACKAGE': enum_definition.enum_package, 'INT_DEF': enum_names_string, - 'SCRIPT_NAME': GetScriptName(), + 'SCRIPT_NAME': java_cpp_utils.GetScriptName(), 'SOURCE_PATH': source_path, 'YEAR': str(date.today().year) }
diff --git a/build/android/gyp/java_cpp_enum.pydeps b/build/android/gyp/java_cpp_enum.pydeps index 32c8de5..d5869ed 100644 --- a/build/android/gyp/java_cpp_enum.pydeps +++ b/build/android/gyp/java_cpp_enum.pydeps
@@ -4,4 +4,5 @@ java_cpp_enum.py util/__init__.py util/build_utils.py +util/java_cpp_utils.py util/md5_check.py
diff --git a/build/android/gyp/java_cpp_enum_tests.py b/build/android/gyp/java_cpp_enum_tests.py index 703293b..5717047c 100755 --- a/build/android/gyp/java_cpp_enum_tests.py +++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -5,7 +5,7 @@ """Tests for enum_preprocess.py. -This test suite containss various tests for the C++ -> Java enum generator. +This test suite contains various tests for the C++ -> Java enum generator. """ import collections @@ -13,8 +13,9 @@ import unittest import java_cpp_enum -from java_cpp_enum import EnumDefinition, GenerateOutput, GetScriptName +from java_cpp_enum import EnumDefinition, GenerateOutput from java_cpp_enum import HeaderParser +from util import java_cpp_utils class TestPreprocess(unittest.TestCase): @@ -65,8 +66,8 @@ long_comment = ('This is a multiple line comment that is really long. ' 'This is a multiple line comment that is') self.assertEqual( - expected % (date.today().year, GetScriptName(), long_comment), - output) + expected % (date.today().year, java_cpp_utils.GetScriptName(), + long_comment), output) def testParseSimpleEnum(self): test_data = """
diff --git a/build/android/gyp/java_cpp_strings.py b/build/android/gyp/java_cpp_strings.py new file mode 100755 index 0000000..59fc04d --- /dev/null +++ b/build/android/gyp/java_cpp_strings.py
@@ -0,0 +1,212 @@ +#!/user/bin/env python +# +# Copyright 2019 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 argparse +import os +import re +import sys +import zipfile + +from util import build_utils +from util import java_cpp_utils + + +def _ToUpper(match): + return match.group(1).upper() + + +def _GetClassName(source_path): + name = os.path.basename(os.path.abspath(source_path)) + (name, _) = os.path.splitext(name) + name = re.sub(r'_([a-z])', _ToUpper, name) + name = re.sub(r'^(.)', _ToUpper, name) + return name + + +class _String(object): + + def __init__(self, name, value, comments): + self.name = java_cpp_utils.KCamelToShouty(name) + self.value = value + self.comments = '\n'.join(' ' + x for x in comments) + + def Format(self): + return '%s\n public static final String %s = %s;' % ( + self.comments, self.name, self.value) + + +def ParseTemplateFile(lines): + package_re = re.compile(r'^package (.*);') + class_re = re.compile(r'.*class (.*) {') + package = '' + class_name = '' + for line in lines: + package_line = package_re.match(line) + if package_line: + package = package_line.groups()[0] + class_line = class_re.match(line) + if class_line: + class_name = class_line.groups()[0] + break + return package, class_name + + +# TODO(crbug.com/937282): It should be possible to parse a file for more than +# string constants. However, this currently only handles extracting string +# constants from a file (and all string constants from that file). Work will +# be needed if we want to annotate specific constants or non string constants +# in the file to be parsed. +class StringFileParser(object): + SINGLE_LINE_COMMENT_RE = re.compile(r'\s*(// [^\n]*)') + STRING_RE = re.compile(r'\s*const char k(.*)\[\]\s*=\s*(?:(".*"))?') + VALUE_RE = re.compile(r'\s*("[^"]*")') + + def __init__(self, lines, path=''): + self._lines = lines + self._path = path + self._in_string = False + self._in_comment = False + self._package = '' + self._current_comments = [] + self._current_name = '' + self._current_value = '' + self._strings = [] + + def _Reset(self): + self._current_comments = [] + self._current_name = '' + self._current_value = '' + self._in_string = False + self._in_comment = False + + def _AppendString(self): + self._strings.append( + _String(self._current_name, self._current_value, + self._current_comments)) + self._Reset() + + def _ParseValue(self, line): + value_line = StringFileParser.VALUE_RE.match(line) + if value_line: + self._current_value = value_line.groups()[0] + self._AppendString() + else: + self._Reset() + + def _ParseComment(self, line): + comment_line = StringFileParser.SINGLE_LINE_COMMENT_RE.match(line) + if comment_line: + self._current_comments.append(comment_line.groups()[0]) + self._in_comment = True + self._in_string = True + return True + else: + self._in_comment = False + return False + + def _ParseString(self, line): + string_line = StringFileParser.STRING_RE.match(line) + if string_line: + self._current_name = string_line.groups()[0] + if string_line.groups()[1]: + self._current_value = string_line.groups()[1] + self._AppendString() + return True + else: + self._in_string = False + return False + + def _ParseLine(self, line): + if not self._in_string: + self._ParseComment(line) + return + + if self._in_comment: + if self._ParseComment(line): + return + if not self._ParseString(line): + self._Reset() + return + + if self._in_string: + self._ParseValue(line) + + def Parse(self): + for line in self._lines: + self._ParseLine(line) + return self._strings + + +def _GenerateOutput(template, source_path, template_path, strings): + description_template = """ + // This following string constants were inserted by + // {SCRIPT_NAME} + // From + // {SOURCE_PATH} + // Into + // {TEMPLATE_PATH} + +""" + values = { + 'SCRIPT_NAME': java_cpp_utils.GetScriptName(), + 'SOURCE_PATH': source_path, + 'TEMPLATE_PATH': template_path, + } + description = description_template.format(**values) + native_strings = '\n\n'.join(x.Format() for x in strings) + + values = { + 'NATIVE_STRINGS': description + native_strings, + } + return template.format(**values) + + +def _ParseStringFile(path): + with open(path) as f: + return StringFileParser(f.readlines(), path).Parse() + + +def _Generate(source_paths, template_path): + with open(template_path) as f: + lines = f.readlines() + template = ''.join(lines) + for source_path in source_paths: + strings = _ParseStringFile(source_path) + package, class_name = ParseTemplateFile(lines) + package_path = package.replace('.', os.path.sep) + file_name = class_name + '.java' + output_path = os.path.join(package_path, file_name) + output = _GenerateOutput(template, source_path, template_path, strings) + yield output, output_path + + +def _Main(argv): + parser = argparse.ArgumentParser() + + parser.add_argument( + '--srcjar', + required=True, + help='When specified, a .srcjar at the given path is ' + 'created instead of individual .java files.') + + parser.add_argument( + '--template', + required=True, + help='Can be used to provide a context into which the' + 'new string constants will be inserted.') + + parser.add_argument( + 'inputs', nargs='+', help='Input file(s)', metavar='INPUTFILE') + args = parser.parse_args(argv) + + with build_utils.AtomicOutput(args.srcjar) as f: + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as srcjar: + for data, path in _Generate(args.inputs, args.template): + build_utils.AddToZipHermetic(srcjar, path, data=data) + + +if __name__ == '__main__': + _Main(sys.argv[1:])
diff --git a/build/android/gyp/java_cpp_strings.pydeps b/build/android/gyp/java_cpp_strings.pydeps new file mode 100644 index 0000000..901b580 --- /dev/null +++ b/build/android/gyp/java_cpp_strings.pydeps
@@ -0,0 +1,8 @@ +# Generated by running: +# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/java_cpp_strings.pydeps build/android/gyp/java_cpp_strings.py +../../gn_helpers.py +java_cpp_strings.py +util/__init__.py +util/build_utils.py +util/java_cpp_utils.py +util/md5_check.py
diff --git a/build/android/gyp/java_cpp_strings_tests.py b/build/android/gyp/java_cpp_strings_tests.py new file mode 100755 index 0000000..d81b336 --- /dev/null +++ b/build/android/gyp/java_cpp_strings_tests.py
@@ -0,0 +1,102 @@ +#!/usr/bin/env python + +# Copyright 2019 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. + +"""Tests for java_cpp_strings.py. + +This test suite contains various tests for the C++ -> Java string generator. +""" + +import unittest + +import java_cpp_strings + + +class _TestStringsParser(unittest.TestCase): + + def testParseComments(self): + test_data = """ +/** + * This should be ignored as well. + */ + +// Comment followed by a blank line. + +// Comment followed by unrelated code. +int foo() { return 3; } + +// Real comment. +const char kASwitch[] = "a-value"; + +// Real comment that spans +// multiple lines. +const char kAnotherSwitch[] = "another-value"; + +// Comment followed by nothing. +""".split('\n') + strings = java_cpp_strings.StringFileParser(test_data).Parse() + self.assertEqual(2, len(strings)) + self.assertEqual('A_SWITCH', strings[0].name) + self.assertEqual('"a-value"', strings[0].value) + self.assertEqual(1, len(strings[0].comments.split('\n'))) + self.assertEqual('ANOTHER_SWITCH', strings[1].name) + self.assertEqual('"another-value"', strings[1].value) + self.assertEqual(2, len(strings[1].comments.split('\n'))) + + def testStringValues(self): + test_data = """ +// Single line string constants. +const char kAString[] = "a-value"; + +// Single line switch with a big space. +const char kAStringWithSpace[] = "a-value"; + +// Wrapped constant definition. +const char kAStringWithAVeryLongNameThatWillHaveToWrap[] = + "a-string-with-a-very-long-name-that-will-have-to-wrap"; + +// This is erroneous and should be ignored. +const char kInvalidLineBreak[] = + + "invalid-line-break"; +""".split('\n') + strings = java_cpp_strings.StringFileParser(test_data).Parse() + self.assertEqual(3, len(strings)) + self.assertEqual('A_STRING', strings[0].name) + self.assertEqual('"a-value"', strings[0].value) + self.assertEqual('A_STRING_WITH_SPACE', strings[1].name) + self.assertEqual('"a-value"', strings[1].value) + self.assertEqual('A_STRING_WITH_A_VERY_LONG_NAME_THAT_WILL_HAVE_TO_WRAP', + strings[2].name) + self.assertEqual('"a-string-with-a-very-long-name-that-will-have-to-wrap"', + strings[2].value) + + def testTemplateParsing(self): + test_data = """ +// Copyright {YEAR} 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. + +// This file is autogenerated by +// {SCRIPT_NAME} +// From +// {SOURCE_PATH}, and +// {TEMPLATE_PATH} + +package my.java.package; + +public any sort of class MyClass {{ + +{NATIVE_STRINGS} + +}} +""".split('\n') + package, class_name = java_cpp_strings.ParseTemplateFile(test_data) + self.assertEqual('my.java.package', package) + self.assertEqual('MyClass', class_name) + + +if __name__ == '__main__': + unittest.main()
diff --git a/build/android/gyp/util/java_cpp_utils.py b/build/android/gyp/util/java_cpp_utils.py new file mode 100755 index 0000000..0b97486 --- /dev/null +++ b/build/android/gyp/util/java_cpp_utils.py
@@ -0,0 +1,32 @@ +#!/user/bin/env python +# +# Copyright 2019 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 os +import re +import sys + + +def GetScriptName(): + return os.path.basename(os.path.abspath(sys.argv[0])) + + +def KCamelToShouty(s): + """Convert |s| from kCamelCase or CamelCase to SHOUTY_CASE. + + kFooBar -> FOO_BAR + FooBar -> FOO_BAR + FooBAR9 -> FOO_BAR9 + FooBARBaz -> FOO_BAR_BAZ + """ + if not re.match(r'^k?([A-Z][^A-Z]+|[A-Z0-9]+)+$', s): + return s + # Strip the leading k. + s = re.sub(r'^k', '', s) + # Add _ between title words and anything else. + s = re.sub(r'([^_])([A-Z][^A-Z_0-9]+)', r'\1_\2', s) + # Add _ between lower -> upper transitions. + s = re.sub(r'([^A-Z_0-9])([A-Z])', r'\1_\2', s) + return s.upper()
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py index 919f506..b98f2a3 100644 --- a/build/android/pylib/constants/__init__.py +++ b/build/android/pylib/constants/__init__.py
@@ -129,24 +129,27 @@ # TODO(jbudorick): Rework this into testing/buildbot/ PYTHON_UNIT_TEST_SUITES = { - 'pylib_py_unittests': { - 'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android'), - 'test_modules': [ - 'devil.android.device_utils_test', - 'devil.android.md5sum_test', - 'devil.utils.cmd_helper_test', - 'pylib.results.json_results_test', - 'pylib.utils.proguard_test', - ] - }, - 'gyp_py_unittests': { - 'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'), - 'test_modules': [ - 'java_cpp_enum_tests', - 'java_google_api_keys_tests', - 'extract_unwind_tables_tests', - ] - }, + 'pylib_py_unittests': { + 'path': + os.path.join(DIR_SOURCE_ROOT, 'build', 'android'), + 'test_modules': [ + 'devil.android.device_utils_test', + 'devil.android.md5sum_test', + 'devil.utils.cmd_helper_test', + 'pylib.results.json_results_test', + 'pylib.utils.proguard_test', + ] + }, + 'gyp_py_unittests': { + 'path': + os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'), + 'test_modules': [ + 'java_cpp_enum_tests', + 'java_cpp_strings_tests', + 'java_google_api_keys_tests', + 'extract_unwind_tables_tests', + ] + }, } LOCAL_MACHINE_TESTS = ['junit', 'python']
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index bcc9c42f..4d6ba29 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -126,6 +126,8 @@ defines += [ "SAFE_BROWSING_DB_LOCAL" ] } else if (safe_browsing_mode == 2) { defines += [ "SAFE_BROWSING_DB_REMOTE" ] + } else if (safe_browsing_mode == 3) { + defines += [ "SAFE_BROWSING_DB_LOCAL" ] } if (is_official_build) { defines += [ "OFFICIAL_BUILD" ]
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index f5cc8e7..a0d7350 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -2417,7 +2417,6 @@ # asset information. # deps: Specifies the dependencies of this target. # dex_path: Path to classes.dex file to include (optional). - # exclude_dex: Omit .dex files from the .apk (optional). # packaged_resources_path: Path to .ap_ to use. # output_apk_path: Output path for the generated .apk. # native_lib_placeholders: List of placeholder filenames to add to the apk @@ -2454,7 +2453,6 @@ _secondary_native_lib_placeholders = invoker.secondary_native_lib_placeholders } - _exclude_dex = defined(invoker.exclude_dex) && invoker.exclude_dex script = "//build/android/gyp/apkbuilder.py" depfile = "$target_gen_dir/$target_name.d" @@ -2520,7 +2518,7 @@ if (defined(invoker.write_asset_list) && invoker.write_asset_list) { args += [ "--write-asset-list" ] } - if (defined(invoker.dex_path) && !_exclude_dex) { + if (defined(invoker.dex_path)) { _rebased_dex_path = rebase_path(invoker.dex_path, root_build_dir) args += [ "--dex-file=$_rebased_dex_path" ] } @@ -2602,7 +2600,6 @@ [ "apk_name", "assets_build_config", - "exclude_dex", "native_lib_placeholders", "native_libs_filearg", "packaged_resources_path",
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 18d6448..2b587d3e 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -635,6 +635,85 @@ } } + # Declare a target for generating Java classes with string constants matching + # those found in C++ files using a python script. + # + # This target will create a single .srcjar. Adding this target to an + # android_library target's srcjar_deps will make the generated java files be + # included in that library's final outputs. + # + # Variables + # sources: list of files to be processed by the script. For each string + # constant in the source files, the script will add a corresponding + # Java string to the specified template file. + # Example + # java_cpp_strings("foo_switches") { + # sources = [ + # "src/foo_switches.cc", + # ] + # template = "src/templates/FooSwitches.java.tmpl + # } + # + # foo_switches.cc: + # + # // A switch. + # const char kASwitch = "a-switch"; + # + # FooSwitches.java.tmpl + # + # // Copyright {YEAR} 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. + # + # // This file is autogenerated by + # // {SCRIPT_NAME} + # // From + # // {SOURCE_PATH}, and + # // {TEMPLATE_PATH} + # + # package my.java.package; + # + # public abstract class FooSwitches {{ + # // ...snip... + # {NATIVE_STRINGS} + # // ...snip... + # }} + # + # result: + # A FooSwitches.java file, defining a class named FooSwitches in the package + # my.java.package. + template("java_cpp_strings") { + set_sources_assignment_filter([]) + action_with_pydeps(target_name) { + forward_variables_from(invoker, + [ + "sources", + "testonly", + "visibility", + ]) + + # The sources aren't compiled so don't check their dependencies. + check_includes = false + script = "//build/android/gyp/java_cpp_strings.py" + + _srcjar_path = "${target_gen_dir}/${target_name}.srcjar" + _rebased_srcjar_path = rebase_path(_srcjar_path, root_build_dir) + _rebased_sources = rebase_path(invoker.sources, root_build_dir) + _rebased_template = rebase_path(invoker.template, root_build_dir) + + args = [ + "--srcjar=$_rebased_srcjar_path", + "--template=$_rebased_template", + ] + args += _rebased_sources + sources += [ invoker.template ] + + outputs = [ + _srcjar_path, + ] + } + } + # Declare a target for processing a Jinja template. # # Variables @@ -1962,7 +2041,6 @@ # resources with acceptable/non-acceptable optimizations. # verify_android_configuration: Enables verification of expected merged # manifest and proguard flags based on a golden file. - # exclude_dex: Omit .dex files (even if they exist) from the final APK. template("android_apk_or_module") { forward_variables_from(invoker, [ "testonly" ]) @@ -2699,7 +2777,6 @@ create_apk("$_create_apk_target") { forward_variables_from(invoker, [ - "exclude_dex", "native_lib_placeholders", "public_deps", "secondary_native_lib_placeholders", @@ -2974,7 +3051,6 @@ "emma_never_instrument", "enable_chromium_linker_tests", "enable_multidex", - "exclude_dex", "final_apk_path", "firebase_app_id", "generate_buildconfig_java", @@ -4267,46 +4343,6 @@ ] } } - - # Generate an APK stub that contains a stripped down version of the manifest, - # a resources.arsc containing only the package name string, and signing - # artifacts. - # - # Variables: - # android_manifest: Path to the android manifest file. - # android_manifest_dep: Target that generates the manifest (optional). - # apk_name: Name of the final .apk. - template("create_stub_apk") { - _stub_manifest = "$target_gen_dir/$target_name/AndroidManifest_stub.xml" - _stub_manifest_target = "${target_name}__stub_manifest" - action(_stub_manifest_target) { - script = "//build/android/gyp/create_stub_manifest.py" - inputs = [ - invoker.android_manifest, - ] - outputs = [ - _stub_manifest, - ] - args = [ - "--input", - rebase_path(invoker.android_manifest), - "--output", - rebase_path(_stub_manifest), - ] - if (defined(invoker.android_manifest_dep)) { - deps = [ - invoker.android_manifest_dep, - ] - } - } - - android_apk(target_name) { - apk_name = invoker.apk_name - android_manifest = _stub_manifest - android_manifest_dep = ":$_stub_manifest_target" - exclude_dex = true - } - } } # Generate an Android resources target that contains localized strings
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index 5b60633c..0b5bbbad 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -211,7 +211,14 @@ # Use lower symbol level in Simple Chrome build for faster link time. # For Simple Chrome, this should take precedence over is_official_build, # turned on by --internal. - symbol_level = 1 + if ((target_cpu == "x64" || target_cpu == "x86") && !is_debug) { + # For release x86/x64 build, specify symbol_level=0 for faster link time. + # x86/x64 shows backtraces with symbol_level=0 (arm requires + # symbol_level=1). + symbol_level = 0 + } else { + symbol_level = 1 + } } else if ((!is_nacl && !is_linux && !is_fuchsia) || is_debug || is_official_build || is_chromecast) { # Linux builds slower by having symbols as part of the target binary,
diff --git a/build/config/coverage/BUILD.gn b/build/config/coverage/BUILD.gn index ae5435bb..2604411 100644 --- a/build/config/coverage/BUILD.gn +++ b/build/config/coverage/BUILD.gn
@@ -25,25 +25,20 @@ } } - # Coverage flags are only on by default when instrument all source files. - # Otherwise, coverage flags are dynamically passed to the compile command - # via the //build/toolchain/clang_code_coverage_wrapper.py script. - if (coverage_instrumentation_input_file == "") { - cflags = [ - "-fprofile-instr-generate", - "-fcoverage-mapping", + cflags = [ + "-fprofile-instr-generate", + "-fcoverage-mapping", - # Following experimental flags removes unused header functions from the - # coverage mapping data embedded in the test binaries, and the reduction - # of binary size enables building Chrome's large unit test targets on - # MacOS. Please refer to crbug.com/796290 for more details. - "-mllvm", - "-limited-coverage-experimental=true", - ] + # Following experimental flags removes unused header functions from the + # coverage mapping data embedded in the test binaries, and the reduction + # of binary size enables building Chrome's large unit test targets on + # MacOS. Please refer to crbug.com/796290 for more details. + "-mllvm", + "-limited-coverage-experimental=true", + ] - if (!is_win) { - cflags += [ "-fno-use-cxa-atexit" ] - } + if (!is_win) { + cflags += [ "-fno-use-cxa-atexit" ] } } }
diff --git a/build/config/features.gni b/build/config/features.gni index b26eb33e..fdf05dfdd 100644 --- a/build/config/features.gni +++ b/build/config/features.gni
@@ -30,12 +30,16 @@ # Variable safe_browsing is used to control the build time configuration for # safe browsing feature. Safe browsing can be compiled in 3 different levels: - # 0 disables it, 1 enables it fully, and 2 enables mobile protection via an - # external API. + # 0 disables it, 1 enables it fully, 2 enables mobile protection via an + # external API, and 3 enables mobile protection via internal API. if (is_ios || is_chromecast) { safe_browsing_mode = 0 } else if (is_android) { - safe_browsing_mode = 2 + if (notouch_build) { + safe_browsing_mode = 3 + } else { + safe_browsing_mode = 2 + } } else { safe_browsing_mode = 1 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index d9d3747..d93fbe46 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -bccf588306321fe071f6421918793ce1ad1c0148 \ No newline at end of file +8d562ec8b8d81d11fa8b6bb199ca07049ab9e074 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 8916285..f5a1ede 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -d2912e75c6c98188ef6e209ef6168974a8ec4320 \ No newline at end of file +6687834853f97abfde3948deff3c7bb37d23ec08 \ No newline at end of file
diff --git a/build/toolchain/clang_code_coverage_wrapper.py b/build/toolchain/clang_code_coverage_wrapper.py index eb493bfa..96978056 100755 --- a/build/toolchain/clang_code_coverage_wrapper.py +++ b/build/toolchain/clang_code_coverage_wrapper.py
@@ -2,11 +2,19 @@ # Copyright 2018 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. -"""Adds code coverage flags to the invocations of the Clang C/C++ compiler. +"""Removes code coverage flags from invocations of the Clang C/C++ compiler. -This script is used to instrument a subset of the source files, and the list of -files to instrument is specified by an input file that is passed to this script -as a command-line argument. +If the GN arg `use_clang_coverage=true`, this script will be invoked by default. +GN will add coverage instrumentation flags to almost all source files. + +This script is used to remove instrumentation flags from a subset of the source +files. By default, it will not remove flags from any files. If the option +--files-to-instrument is passed, this script will remove flags from all files +except the ones listed in --files-to-instrument. + +This script also contains hard-coded exclusion lists of files to never +instrument, indexed by target operating system. Files in these lists have their +flags removed in both modes. The OS can be selected with --target-os. The path to the coverage instrumentation input file should be relative to the root build directory, and the file consists of multiple lines where each line @@ -37,6 +45,8 @@ import sys # Flags used to enable coverage instrumentation. +# Flags should be listed in the same order that they are added in +# build/config/coverage/BUILD.gn _COVERAGE_FLAGS = [ '-fprofile-instr-generate', '-fcoverage-mapping', # Following experimental flags remove unused header functions from the @@ -46,6 +56,41 @@ '-mllvm', '-limited-coverage-experimental=true' ] +# Map of exclusion lists indexed by target OS. +# If no target OS is defined, or one is defined that doesn't have a specific +# entry, use the 'default' exclusion_list. Anything added to 'default' will +# apply to all platforms that don't have their own specific list. +_COVERAGE_EXCLUSION_LIST_MAP = { + 'default': [], + 'chromeos': [ + # These files caused clang to crash while compiling them. They are + # excluded pending an investigation into the underlying compiler bug. + '../../third_party/webrtc/p2p/base/p2p_transport_channel.cc', + '../../third_party/icu/source/common/uts46.cpp', + '../../third_party/icu/source/common/ucnvmbcs.cpp', + '../../base/android/android_image_reader_compat.cc', + ] +} + + +def _remove_flags_from_command(command): + # We need to remove the coverage flags for this file, but we only want to + # remove them if we see the exact sequence defined in _COVERAGE_FLAGS. + # That ensures that we only remove the flags added by GN when + # "use_clang_coverage" is true. Otherwise, we would remove flags set by + # other parts of the build system. + start_flag = _COVERAGE_FLAGS[0] + num_flags = len(_COVERAGE_FLAGS) + start_idx = 0 + try: + while True: + idx = command.index(start_flag, start_idx) + start_idx = idx + 1 + if command[idx:idx+num_flags] == _COVERAGE_FLAGS: + del command[idx:idx+num_flags] + break + except ValueError: + pass def main(): # TODO(crbug.com/898695): Make this wrapper work on Windows platform. @@ -54,16 +99,23 @@ arg_parser.add_argument( '--files-to-instrument', type=str, - required=True, help='Path to a file that contains a list of file names to instrument.') + arg_parser.add_argument( + '--target-os', + required=False, + help='The OS to compile for.') arg_parser.add_argument('args', nargs=argparse.REMAINDER) parsed_args = arg_parser.parse_args() - if not os.path.isfile(parsed_args.files_to_instrument): + if (parsed_args.files_to_instrument and + not os.path.isfile(parsed_args.files_to_instrument)): raise Exception('Path to the coverage instrumentation file: "%s" doesn\'t ' 'exist.' % parsed_args.files_to_instrument) compile_command = parsed_args.args + if not any('clang' in s for s in compile_command): + return subprocess.call(compile_command) + try: # The command is assumed to use Clang as the compiler, and the path to the # source file is behind the -c argument, and the path to the source path is @@ -79,12 +131,19 @@ raise Exception('Source file to be compiled is missing from the command.') compile_source_file = compile_command[index_dash_c + 1] - with open(parsed_args.files_to_instrument) as f: - if compile_source_file + '\n' in f.read(): - compile_command.extend(_COVERAGE_FLAGS) + target_os = parsed_args.target_os + if target_os not in _COVERAGE_EXCLUSION_LIST_MAP: + target_os = 'default' + exclusion_list = _COVERAGE_EXCLUSION_LIST_MAP[target_os] + + if compile_source_file in exclusion_list: + _remove_flags_from_command(compile_command) + elif parsed_args.files_to_instrument: + with open(parsed_args.files_to_instrument) as f: + if compile_source_file not in f.read(): + _remove_flags_from_command(compile_command) return subprocess.call(compile_command) - if __name__ == '__main__': sys.exit(main())
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index 47f18c8a..7326a84 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -194,25 +194,48 @@ compiler_prefix = "${analyzer_wrapper} " + compiler_prefix } - if (defined(toolchain_args.coverage_instrumentation_input_file)) { - toolchain_coverage_instrumentation_input_file = - toolchain_args.coverage_instrumentation_input_file + # A specific toolchain may wish to avoid coverage instrumentation, so we + # allow the global "use_clang_coverage" arg to be overridden. + if (defined(toolchain_args.use_clang_coverage)) { + toolchain_use_clang_coverage = toolchain_args.use_clang_coverage } else { - toolchain_coverage_instrumentation_input_file = - coverage_instrumentation_input_file + toolchain_use_clang_coverage = use_clang_coverage } - _use_clang_coverage_wrapper = - toolchain_coverage_instrumentation_input_file != "" - if (_use_clang_coverage_wrapper) { + + # For a coverage build, we use the wrapper script globally so that it can + # remove coverage cflags from files that should not have them. + if (toolchain_use_clang_coverage) { assert(!use_clang_static_analyzer, "Clang static analyzer wrapper and Clang code coverage wrapper " + "cannot be used together.") + # "coverage_instrumentation_input_file" is set in args.gn, but it can be + # overridden by a toolchain config. + if (defined(toolchain_args.coverage_instrumentation_input_file)) { + toolchain_coverage_instrumentation_input_file = + toolchain_args.coverage_instrumentation_input_file + } else { + toolchain_coverage_instrumentation_input_file = + coverage_instrumentation_input_file + } + _coverage_wrapper = rebase_path("//build/toolchain/clang_code_coverage_wrapper.py", - root_build_dir) + " --files-to-instrument=" + - rebase_path(toolchain_coverage_instrumentation_input_file, root_build_dir) + + # The wrapper needs to know what OS we target because it uses that to + # select a list of files that should not be instrumented. + _coverage_wrapper = _coverage_wrapper + " --target-os=" + target_os + + # We want to instrument everything if there is no input file set. + # If there is a file we need to give it to the wrapper script so it can + # instrument only those files. + if (toolchain_coverage_instrumentation_input_file != "") { + _coverage_wrapper = + _coverage_wrapper + " --files-to-instrument=" + + rebase_path(toolchain_coverage_instrumentation_input_file, + root_build_dir) + } compiler_prefix = "${_coverage_wrapper} " + compiler_prefix }
diff --git a/cc/OWNERS b/cc/OWNERS index e12309d..4d4bbfa 100644 --- a/cc/OWNERS +++ b/cc/OWNERS
@@ -48,6 +48,9 @@ # input, scrolling bokan@chromium.org +# scroll snap +majidvp@chromium.org + # general enne@chromium.org danakj@chromium.org
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h index 352b71bd..0315c2c 100644 --- a/cc/layers/heads_up_display_layer_impl.h +++ b/cc/layers/heads_up_display_layer_impl.h
@@ -14,7 +14,6 @@ #include "base/time/time.h" #include "cc/cc_export.h" #include "cc/layers/layer_impl.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/resources/memory_history.h" #include "cc/resources/resource_pool.h" #include "cc/trees/debug_rect_history.h" @@ -159,9 +158,6 @@ base::TimeTicks time_of_last_graph_update_; - // color space for OOPR - const RasterColorSpace raster_color_space_; - DISALLOW_COPY_AND_ASSIGN(HeadsUpDisplayLayerImpl); };
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn index ddfa824..6c428fba 100644 --- a/cc/paint/BUILD.gn +++ b/cc/paint/BUILD.gn
@@ -8,8 +8,6 @@ cc_component("paint") { output_name = "cc_paint" sources = [ - "color_space_transfer_cache_entry.cc", - "color_space_transfer_cache_entry.h", "decode_stashing_image_provider.cc", "decode_stashing_image_provider.h", "decoded_draw_image.cc",
diff --git a/cc/paint/color_space_transfer_cache_entry.cc b/cc/paint/color_space_transfer_cache_entry.cc deleted file mode 100644 index 31f2743..0000000 --- a/cc/paint/color_space_transfer_cache_entry.cc +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2018 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 "cc/paint/color_space_transfer_cache_entry.h" - -#include "ui/gfx/ipc/color/gfx_param_traits.h" - -namespace cc { - -ClientColorSpaceTransferCacheEntry::ClientColorSpaceTransferCacheEntry( - const RasterColorSpace& raster_color_space) - : id_(raster_color_space.color_space_id) { - DCHECK(raster_color_space.color_space.IsValid()); - IPC::ParamTraits<gfx::ColorSpace>::Write(&pickle_, - raster_color_space.color_space); - DCHECK_LE(pickle_.size(), UINT32_MAX); -} - -ClientColorSpaceTransferCacheEntry::~ClientColorSpaceTransferCacheEntry() = - default; - -uint32_t ClientColorSpaceTransferCacheEntry::Id() const { - return id_; -} - -uint32_t ClientColorSpaceTransferCacheEntry::SerializedSize() const { - return static_cast<uint32_t>(pickle_.size()); -} - -bool ClientColorSpaceTransferCacheEntry::Serialize( - base::span<uint8_t> data) const { - DCHECK_GE(data.size(), pickle_.size()); - memcpy(data.data(), pickle_.data(), pickle_.size()); - return true; -} - -ServiceColorSpaceTransferCacheEntry::ServiceColorSpaceTransferCacheEntry() = - default; - -ServiceColorSpaceTransferCacheEntry::~ServiceColorSpaceTransferCacheEntry() = - default; - -size_t ServiceColorSpaceTransferCacheEntry::CachedSize() const { - return sizeof(gfx::ColorSpace); -} - -bool ServiceColorSpaceTransferCacheEntry::Deserialize( - GrContext* context, - base::span<const uint8_t> data) { - base::Pickle pickle(reinterpret_cast<const char*>(data.data()), data.size()); - base::PickleIterator iterator(pickle); - if (!IPC::ParamTraits<gfx::ColorSpace>::Read(&pickle, &iterator, - &color_space_)) - return false; - return color_space_.IsValid(); -} - -} // namespace cc
diff --git a/cc/paint/color_space_transfer_cache_entry.h b/cc/paint/color_space_transfer_cache_entry.h deleted file mode 100644 index 4923c73..0000000 --- a/cc/paint/color_space_transfer_cache_entry.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2018 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 CC_PAINT_COLOR_SPACE_TRANSFER_CACHE_ENTRY_H_ -#define CC_PAINT_COLOR_SPACE_TRANSFER_CACHE_ENTRY_H_ - -#include "base/containers/span.h" -#include "base/pickle.h" -#include "cc/paint/paint_export.h" -#include "cc/paint/transfer_cache_entry.h" -#include "ui/gfx/color_space.h" - -namespace cc { - -struct RasterColorSpace { - RasterColorSpace() = default; - RasterColorSpace(const gfx::ColorSpace& color_space, int color_space_id) - : color_space(color_space), color_space_id(color_space_id) {} - - gfx::ColorSpace color_space; - int color_space_id = -1; -}; - -class CC_PAINT_EXPORT ClientColorSpaceTransferCacheEntry final - : public ClientTransferCacheEntryBase<TransferCacheEntryType::kColorSpace> { - public: - explicit ClientColorSpaceTransferCacheEntry( - const RasterColorSpace& raster_color_space); - ~ClientColorSpaceTransferCacheEntry() override; - uint32_t Id() const override; - uint32_t SerializedSize() const override; - bool Serialize(base::span<uint8_t> data) const final; - - private: - int id_; - base::Pickle pickle_; -}; - -class CC_PAINT_EXPORT ServiceColorSpaceTransferCacheEntry final - : public ServiceTransferCacheEntryBase< - TransferCacheEntryType::kColorSpace> { - public: - ServiceColorSpaceTransferCacheEntry(); - ~ServiceColorSpaceTransferCacheEntry() override; - size_t CachedSize() const override; - bool Deserialize(GrContext* context, base::span<const uint8_t> data) override; - - const gfx::ColorSpace& color_space() const { return color_space_; } - - private: - gfx::ColorSpace color_space_; -}; - -} // namespace cc - -#endif // CC_PAINT_COLOR_SPACE_TRANSFER_CACHE_ENTRY_H_
diff --git a/cc/paint/transfer_cache_entry.cc b/cc/paint/transfer_cache_entry.cc index d87ac46..4d519b66 100644 --- a/cc/paint/transfer_cache_entry.cc +++ b/cc/paint/transfer_cache_entry.cc
@@ -7,7 +7,6 @@ #include <memory> #include "base/logging.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/image_transfer_cache_entry.h" #include "cc/paint/raw_memory_transfer_cache_entry.h" #include "cc/paint/shader_transfer_cache_entry.h" @@ -21,8 +20,6 @@ return std::make_unique<ServiceRawMemoryTransferCacheEntry>(); case TransferCacheEntryType::kImage: return std::make_unique<ServiceImageTransferCacheEntry>(); - case TransferCacheEntryType::kColorSpace: - return std::make_unique<ServiceColorSpaceTransferCacheEntry>(); case TransferCacheEntryType::kShader: // ServiceShader/TextBlobTransferCache is only created via // CreateLocalEntry and is never serialized/deserialized. @@ -46,7 +43,6 @@ bool ServiceTransferCacheEntry::UsesGrContext(TransferCacheEntryType type) { switch (type) { case TransferCacheEntryType::kRawMemory: - case TransferCacheEntryType::kColorSpace: case TransferCacheEntryType::kShader: return false; case TransferCacheEntryType::kImage:
diff --git a/cc/paint/transfer_cache_entry.h b/cc/paint/transfer_cache_entry.h index 5f7dabe1..ec5f6270 100644 --- a/cc/paint/transfer_cache_entry.h +++ b/cc/paint/transfer_cache_entry.h
@@ -22,7 +22,6 @@ enum class TransferCacheEntryType : uint32_t { kRawMemory, kImage, - kColorSpace, kShader, // Add new entries above this line, make sure to update kLast. kLast = kShader,
diff --git a/cc/raster/raster_source.h b/cc/raster/raster_source.h index b73992a..d4d45ff5 100644 --- a/cc/raster/raster_source.h +++ b/cc/raster/raster_source.h
@@ -14,7 +14,6 @@ #include "cc/cc_export.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/layers/recording_source.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/image_id.h" #include "third_party/skia/include/core/SkPicture.h" #include "ui/gfx/color_space.h" @@ -40,8 +39,6 @@ bool use_lcd_text = true; ImageProvider* image_provider = nullptr; - - RasterColorSpace raster_color_space; }; // Helper function to apply a few common operations before passing the canvas
diff --git a/cc/test/fake_tile_manager_client.cc b/cc/test/fake_tile_manager_client.cc index 0b9acc3..8411d78 100644 --- a/cc/test/fake_tile_manager_client.cc +++ b/cc/test/fake_tile_manager_client.cc
@@ -23,8 +23,8 @@ return nullptr; } -RasterColorSpace FakeTileManagerClient::GetRasterColorSpace() const { - return RasterColorSpace(); +const gfx::ColorSpace& FakeTileManagerClient::GetRasterColorSpace() const { + return color_space_; } size_t FakeTileManagerClient::GetFrameIndexForImage(
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h index dd8be51..791beb93 100644 --- a/cc/test/fake_tile_manager_client.h +++ b/cc/test/fake_tile_manager_client.h
@@ -27,10 +27,13 @@ std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue( TreePriority tree_priority) override; void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override {} - RasterColorSpace GetRasterColorSpace() const override; + const gfx::ColorSpace& GetRasterColorSpace() const override; void RequestImplSideInvalidationForCheckerImagedTiles() override {} size_t GetFrameIndexForImage(const PaintImage& paint_image, WhichTree tree) const override; + + private: + gfx::ColorSpace color_space_; }; } // namespace cc
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc index ae2af26..43d282e6 100644 --- a/cc/tiles/tile_manager.cc +++ b/cc/tiles/tile_manager.cc
@@ -1172,7 +1172,7 @@ tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(), &invalidated_rect); } - const RasterColorSpace& raster_color_space = client_->GetRasterColorSpace(); + const gfx::ColorSpace& raster_color_space = client_->GetRasterColorSpace(); bool partial_tile_decode = false; if (resource) { resource_content_id = tile->invalidated_id(); @@ -1181,7 +1181,7 @@ } else { resource = resource_pool_->AcquireResource(tile->desired_texture_size(), DetermineResourceFormat(tile), - raster_color_space.color_space); + raster_color_space); DCHECK(resource); } @@ -1269,9 +1269,6 @@ PlaybackImageProvider image_provider(image_controller_.cache(), std::move(settings)); - - playback_settings.raster_color_space = raster_color_space; - PaintWorkletImageProvider paint_worklet_image_provider( image_controller_.paint_worklet_image_cache()); DispatchingImageProvider dispatching_image_provider(
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h index 244eea4..c4024e2 100644 --- a/cc/tiles/tile_manager.h +++ b/cc/tiles/tile_manager.h
@@ -18,7 +18,6 @@ #include "base/sequenced_task_runner.h" #include "base/values.h" #include "cc/base/unique_notifier.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/raster/raster_buffer_provider.h" #include "cc/raster/raster_source.h" #include "cc/resources/memory_history.h" @@ -82,7 +81,7 @@ virtual void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) = 0; // Requests the color space into which tiles should be rasterized. - virtual RasterColorSpace GetRasterColorSpace() const = 0; + virtual const gfx::ColorSpace& GetRasterColorSpace() const = 0; // Requests that a pending tree be scheduled to invalidate content on the // pending on active tree. This is currently used when tiles that are @@ -199,7 +198,7 @@ resource_pool_->AcquireResource( tiles[i]->desired_texture_size(), raster_buffer_provider_->GetResourceFormat(), - client_->GetRasterColorSpace().color_space); + client_->GetRasterColorSpace()); raster_buffer_provider_->AcquireBufferForRaster(resource, 0, 0); // The raster here never really happened, cuz tests. So just add an // arbitrary sync token.
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 483243c..51e5f965c 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1573,16 +1573,22 @@ is_likely_to_require_a_draw_ = is_likely_to_require_a_draw; } -RasterColorSpace LayerTreeHostImpl::GetRasterColorSpace() const { - RasterColorSpace result; +const gfx::ColorSpace& LayerTreeHostImpl::GetRasterColorSpace() const { + int dummy; + return GetRasterColorSpaceAndId(&dummy); +} + +const gfx::ColorSpace& LayerTreeHostImpl::GetRasterColorSpaceAndId( + int* id) const { + const gfx::ColorSpace* result = nullptr; // The pending tree will have the most recently updated color space, so // prefer that. if (pending_tree_) { - result.color_space = pending_tree_->raster_color_space(); - result.color_space_id = pending_tree_->raster_color_space_id(); + result = &pending_tree_->raster_color_space(); + *id = pending_tree_->raster_color_space_id(); } else if (active_tree_) { - result.color_space = active_tree_->raster_color_space(); - result.color_space_id = active_tree_->raster_color_space_id(); + result = &active_tree_->raster_color_space(); + *id = active_tree_->raster_color_space_id(); } // If we are likely to software composite the resource, we use sRGB because @@ -1591,11 +1597,11 @@ // (not specifying a color space indicates that no color conversion is // required). if (!layer_tree_frame_sink_ || !layer_tree_frame_sink_->context_provider() || - !result.color_space.IsValid()) { - result.color_space = default_color_space_; - result.color_space_id = default_color_space_id_; + !result || !result->IsValid()) { + result = &default_color_space_; + *id = default_color_space_id_; } - return result; + return *result; } void LayerTreeHostImpl::RequestImplSideInvalidationForCheckerImagedTiles() { @@ -2382,7 +2388,8 @@ // For simplicity, clobber all resources when the color space changes. // This is mostly to clear the image decode caches, which don't handle // multiple color space at once. - int color_space_id = GetRasterColorSpace().color_space_id; + int color_space_id = -1; + GetRasterColorSpaceAndId(&color_space_id); bool color_space_changed = last_color_space_id_ != color_space_id; last_color_space_id_ = color_space_id; @@ -3060,14 +3067,14 @@ tile_format), settings_.decoded_image_working_set_budget_bytes, max_texture_size_, paint_image_generator_client_id_, - GetRasterColorSpace().color_space.ToSkColorSpace()); + GetRasterColorSpace().ToSkColorSpace()); } else { bool gpu_compositing = !!layer_tree_frame_sink_->context_provider(); image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>( viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format), settings_.decoded_image_working_set_budget_bytes, paint_image_generator_client_id_, - GetRasterColorSpace().color_space.ToSkColorSpace()); + GetRasterColorSpace().ToSkColorSpace()); } // Pass the single-threaded synchronous task graph runner to the worker pool
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index bbcdfce..6f07f25 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -427,7 +427,7 @@ std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue( TreePriority tree_priority) override; void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override; - RasterColorSpace GetRasterColorSpace() const override; + const gfx::ColorSpace& GetRasterColorSpace() const override; void RequestImplSideInvalidationForCheckerImagedTiles() override; size_t GetFrameIndexForImage(const PaintImage& paint_image, WhichTree tree) const override; @@ -759,6 +759,8 @@ BeginFrameTracker current_begin_frame_tracker_; private: + const gfx::ColorSpace& GetRasterColorSpaceAndId(int* id) const; + void CollectScrollDeltas(ScrollAndScaleSet* scroll_info) const; void CollectScrollbarUpdates(ScrollAndScaleSet* scroll_info) const;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 97ef9ed..8288c54dd 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -13630,12 +13630,11 @@ LayerTreeSettings settings = DefaultSettings(); CreateHostImpl(settings, CreateLayerTreeFrameSink()); // The default raster color space should be sRGB. - EXPECT_EQ(host_impl_->GetRasterColorSpace().color_space, - gfx::ColorSpace::CreateSRGB()); + EXPECT_EQ(host_impl_->GetRasterColorSpace(), gfx::ColorSpace::CreateSRGB()); // The raster color space should update with tree activation. host_impl_->active_tree()->SetRasterColorSpace( 2, gfx::ColorSpace::CreateDisplayP3D65()); - EXPECT_EQ(host_impl_->GetRasterColorSpace().color_space, + EXPECT_EQ(host_impl_->GetRasterColorSpace(), gfx::ColorSpace::CreateDisplayP3D65()); } @@ -13643,12 +13642,10 @@ LayerTreeSettings settings = DefaultSettings(); CreateHostImpl(settings, FakeLayerTreeFrameSink::CreateSoftware()); // Software composited resources should always use sRGB as their color space. - EXPECT_EQ(host_impl_->GetRasterColorSpace().color_space, - gfx::ColorSpace::CreateSRGB()); + EXPECT_EQ(host_impl_->GetRasterColorSpace(), gfx::ColorSpace::CreateSRGB()); host_impl_->active_tree()->SetRasterColorSpace( 2, gfx::ColorSpace::CreateDisplayP3D65()); - EXPECT_EQ(host_impl_->GetRasterColorSpace().color_space, - gfx::ColorSpace::CreateSRGB()); + EXPECT_EQ(host_impl_->GetRasterColorSpace(), gfx::ColorSpace::CreateSRGB()); } TEST_F(LayerTreeHostImplTest, UpdatedTilingsForNonDrawingLayers) {
diff --git a/chrome/MAJOR_BRANCH_DATE b/chrome/MAJOR_BRANCH_DATE index 3d70feb..7ba2073 100644 --- a/chrome/MAJOR_BRANCH_DATE +++ b/chrome/MAJOR_BRANCH_DATE
@@ -1 +1 @@ -MAJOR_BRANCH_DATE=2019-01-25 +MAJOR_BRANCH_DATE=2019-03-08
diff --git a/chrome/VERSION b/chrome/VERSION index 0123f0e..da3bc62 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ -MAJOR=74 +MAJOR=75 MINOR=0 -BUILD=3728 +BUILD=3730 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index db5560ca..08e8ab0 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -136,6 +136,16 @@ } } +if (notouch_build) { + android_resources("chrome_touchless_java_resources") { + resource_dirs = [ "//chrome/android/touchless/java/res" ] + deps = [ + ":chrome_app_java_resources", + ] + custom_package = "org.chromium.chrome.touchless" + } +} + android_resources("chrome_download_java_resources") { resource_dirs = [ "//chrome/android/java/res_download" ] deps = [ @@ -355,6 +365,7 @@ srcjar_deps = [ ":chrome_android_java_enums_srcjar", + ":chrome_android_java_switches_srcjar", ":chrome_android_java_google_api_keys_srcjar", ":photo_picker_aidl", ":resource_id_javagen", @@ -417,6 +428,9 @@ ] } srcjar_deps += [ ":chrome_vr_android_java_enums_srcjar" ] + if (notouch_build) { + deps += [ ":chrome_touchless_java_resources" ] + } # Add the actual implementation where necessary so that downstream targets # can provide their own implementations. @@ -436,10 +450,6 @@ "//chrome/android/features/autofill_assistant:java", "//chrome/android/features/media_router:java", ] - - if (notouch_build) { - deps += [ "//chrome/android/features/touchless:java" ] - } } android_library("bundle_canary_java") { @@ -496,6 +506,13 @@ ] } +java_cpp_strings("chrome_android_java_switches_srcjar") { + sources = [ + "//chrome/common/chrome_switches.cc", + ] + template = "//chrome/android/java_templates/ChromeSwitches.java.tmpl" +} + proto_java_library("document_tab_model_info_proto_java") { proto_path = "java/src/org/chromium/chrome/browser/tabmodel/document" sources = [ @@ -718,6 +735,7 @@ "//components/web_restrictions:provider_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", + "//media/base/android:java_switches", "//media/base/android:media_java", "//mojo/public/java:bindings_java", "//mojo/public/java:system_java", @@ -1695,6 +1713,13 @@ } } +# TODO(estevenson): Remove this once we switch to using bundle targets to +# generate APK stubs. +android_resources("trichrome_dummy_resources") { + custom_package = "org.chromium.trichromelibrary" + resource_dirs = [ "trichrome/res_dummy" ] +} + monochrome_public_apk_or_module_tmpl("trichrome_chrome_apk") { apk_name = "TrichromeChrome" target_type = "android_apk" @@ -1814,7 +1839,6 @@ ":chrome_test_java", "//chrome/android/features/autofill_assistant:test_java", "//chrome/android/features/media_router:test_java", - "//chrome/android/features/touchless:touchless_java_test", "//chrome/android/webapk/libs/runtime_library:runtime_library_javatests", "//chrome/android/webapk/shell_apk:shell_apk_javatests", "//chrome/browser/profiling_host:profiling_host_javatests",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index 7d9af53..f2833952 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -30,6 +30,7 @@ "channel=$android_channel", "enable_vr=$enable_vr", "include_arcore_manifest_flag=$package_arcore", + "notouch_build=$notouch_build", ] # A template used to declare any target that will implement a full Chromium
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index fc7d093..9b73788 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -54,7 +54,6 @@ "java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestOptions.java", "java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequest.java", "java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequestSection.java", - "java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestBottomBar.java", "java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestUI.java", ] }
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request.xml index 5fcba66..6eb21d64 100644 --- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request.xml +++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request.xml
@@ -67,7 +67,4 @@ android:text="@string/autofill_assistant_3rd_party_privacy_notice" android:textAppearance="@style/TextAppearance.AssistantBlackCaption" android:background="@drawable/autofill_assistant_lightblue_rect_bg"/> - - <include layout="@layout/autofill_assistant_payment_request_bottom_bar" /> - </org.chromium.chrome.browser.widget.BoundedLinearLayout>
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request_bottom_bar.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request_bottom_bar.xml deleted file mode 100644 index 027daa0..0000000 --- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_payment_request_bottom_bar.xml +++ /dev/null
@@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 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. --> - -<!-- Autofill Assistant specific bottom of the payment request UI. --> -<org.chromium.chrome.browser.autofill_assistant.payment.PaymentRequestBottomBar - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/bottom_bar" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:paddingTop="@dimen/editor_dialog_section_large_spacing" - android:background="@color/modern_primary_color" - android:gravity="end" - android:orientation="horizontal" - android:visibility="gone" > - - <org.chromium.ui.widget.ButtonCompat - android:id="@+id/button_secondary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/autofill_assistant_bottombar_horizontal_spacing" - android:minHeight="36dp" - android:text="@string/cancel" - style="@style/TextButton" /> - - <org.chromium.ui.widget.ButtonCompat - android:id="@+id/button_primary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minHeight="36dp" - android:text="@string/next" - style="@style/FilledButton.Flat" /> -</org.chromium.chrome.browser.autofill_assistant.payment.PaymentRequestBottomBar>
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java index 9ee3ffb..fc864cf 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -16,6 +16,7 @@ import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselModel; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip; +import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip.Type; import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; @@ -24,7 +25,6 @@ import org.chromium.content_public.browser.WebContents; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -201,22 +201,17 @@ for (int i = 0; i < texts.length; i++) { final int suggestionIndex = i; chips.add(new AssistantChip(AssistantChip.Type.CHIP_ASSISTIVE, texts[i], - () -> safeNativeOnSuggestionSelected(suggestionIndex))); + /* disabled= */ false, () -> safeNativeOnSuggestionSelected(suggestionIndex))); } AssistantCarouselModel model = getModel().getSuggestionsModel(); model.set(ALIGNMENT, AssistantCarouselModel.Alignment.START); setChips(model, chips); } - @CalledByNative - private void clearActions() { - getModel().getActionsModel().getChipsModel().set(Collections.emptyList()); - } - /** Creates an empty list of chips. */ @CalledByNative private static List<AssistantChip> createChipList() { - return new ArrayList<AssistantChip>(); + return new ArrayList<>(); } /** @@ -224,7 +219,7 @@ */ @CalledByNative private void addActionButton(List<AssistantChip> chips, String text, int actionIndex) { - chips.add(new AssistantChip(AssistantChip.Type.BUTTON_HAIRLINE, text, + chips.add(new AssistantChip(AssistantChip.Type.BUTTON_HAIRLINE, text, /* disabled= */ false, () -> safeNativeOnActionSelected(actionIndex))); } @@ -234,8 +229,8 @@ */ @CalledByNative private void addHighlightedActionButton( - List<AssistantChip> chips, String text, int actionIndex) { - chips.add(new AssistantChip(AssistantChip.Type.BUTTON_FILLED_BLUE, text, + List<AssistantChip> chips, String text, int actionIndex, boolean disabled) { + chips.add(new AssistantChip(Type.BUTTON_FILLED_BLUE, text, disabled, () -> safeNativeOnActionSelected(actionIndex))); } @@ -245,7 +240,7 @@ */ @CalledByNative private void addCancelButton(List<AssistantChip> chips, String text, int actionIndex) { - chips.add(new AssistantChip(AssistantChip.Type.BUTTON_HAIRLINE, text, + chips.add(new AssistantChip(AssistantChip.Type.BUTTON_HAIRLINE, text, /* disabled= */ false, () -> safeNativeOnCancelButtonClicked(actionIndex))); } @@ -254,8 +249,8 @@ */ @CalledByNative private void addCloseButton(List<AssistantChip> chips, String text) { - chips.add(new AssistantChip( - AssistantChip.Type.BUTTON_HAIRLINE, text, this::safeNativeOnCloseButtonClicked)); + chips.add(new AssistantChip(AssistantChip.Type.BUTTON_HAIRLINE, text, /* disabled= */ false, + this::safeNativeOnCloseButtonClicked)); } @CalledByNative
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java index 821a5c42..6a792ed 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
@@ -38,8 +38,8 @@ mView.setLayoutManager(mLayoutManager); mView.addItemDecoration(new SpaceItemDecoration(context)); mView.setAdapter(new RecyclerViewAdapter<>( - new SimpleRecyclerViewMcp<>(model.getChipsModel(), AssistantChip::getType, - AssistantChipViewHolder::bind), + new SimpleRecyclerViewMcp<>(model.getChipsModel(), + AssistantChipViewHolder::getViewType, AssistantChipViewHolder::bind), AssistantChipViewHolder::create)); // Carousel is initially hidden.
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java index e6b9ed9..f246287f 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChip.java
@@ -13,24 +13,27 @@ * A chip to display to the user. */ public class AssistantChip { - @IntDef({Type.CHIP_ASSISTIVE, Type.BUTTON_FILLED_BLUE, Type.BUTTON_HAIRLINE, - Type.BUTTON_FILLED_DISABLED}) + @IntDef({Type.CHIP_ASSISTIVE, Type.BUTTON_FILLED_BLUE, Type.BUTTON_HAIRLINE}) @Retention(RetentionPolicy.SOURCE) public @interface Type { int CHIP_ASSISTIVE = 0; int BUTTON_FILLED_BLUE = 1; int BUTTON_HAIRLINE = 2; - int BUTTON_FILLED_DISABLED = 3; + + /** The number of types. Increment this value if you add a type. */ + int CHIP_TYPE_NUMBER = 3; } private final @Type int mType; private final String mText; + private final boolean mDisabled; private final Runnable mSelectedListener; - public AssistantChip(@Type int type, String text, Runnable selectedListener) { + public AssistantChip(@Type int type, String text, boolean disabled, Runnable selectedListener) { mType = type; mText = text; mSelectedListener = selectedListener; + mDisabled = disabled; } public int getType() { @@ -41,6 +44,10 @@ return mText; } + public boolean isDisabled() { + return mDisabled; + } + public Runnable getSelectedListener() { return mSelectedListener; }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java index f83d313..5f7a682 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
@@ -26,12 +26,11 @@ static AssistantChipViewHolder create(ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); int resId = -1; - switch (viewType) { + switch (viewType % AssistantChip.Type.CHIP_TYPE_NUMBER) { // TODO: inflate normal chrome buttons instead. case AssistantChip.Type.CHIP_ASSISTIVE: resId = R.layout.autofill_assistant_chip_assistive; break; - case AssistantChip.Type.BUTTON_FILLED_DISABLED: case AssistantChip.Type.BUTTON_FILLED_BLUE: resId = R.layout.autofill_assistant_button_filled; break; @@ -43,13 +42,24 @@ } TextView view = (TextView) layoutInflater.inflate(resId, /* root= */ null); - if (viewType == AssistantChip.Type.BUTTON_FILLED_DISABLED) { + if (viewType >= AssistantChip.Type.CHIP_TYPE_NUMBER) { view.setEnabled(false); } return new AssistantChipViewHolder(view); } + static int getViewType(AssistantChip chip) { + // We add AssistantChip.Type.CHIP_TYPE_NUMBER to differentiate between enabled and disabled + // chips of the same type. Ideally, we should return a (type, disabled) tuple but + // RecyclerView does not allow that. + if (chip.isDisabled()) { + return chip.getType() + AssistantChip.Type.CHIP_TYPE_NUMBER; + } + + return chip.getType(); + } + public void bind(AssistantChip chip) { mText.setText(chip.getText()); mText.setOnClickListener(ignoredView -> chip.getSelectedListener().run());
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java index fe3dd0b..10e64d8 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java
@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.autofill.PersonalDataManager; +import org.chromium.chrome.browser.payments.AutofillContact; /** Delegate for the Payment Request UI. */ @JNINamespace("autofill_assistant") @@ -25,20 +26,37 @@ mNativeAssistantOverlayDelegate = nativeAssistantPaymentRequestDelegate; } - public void onPaymentInformationSelected( - AutofillAssistantPaymentRequest.SelectedPaymentInformation selectedInformation) { + public void onContactInfoChanged(AutofillContact contact) { if (mNativeAssistantOverlayDelegate != 0) { - nativeOnGetPaymentInformation(mNativeAssistantOverlayDelegate, - selectedInformation.succeed, selectedInformation.card, - selectedInformation.address, selectedInformation.payerName, - selectedInformation.payerPhone, selectedInformation.payerEmail, - selectedInformation.isTermsAndConditionsAccepted); + String name = null; + String phone = null; + String email = null; + + if (contact != null) { + name = contact.getPayerName(); + phone = contact.getPayerPhone(); + email = contact.getPayerEmail(); + } + + nativeOnContactInfoChanged(mNativeAssistantOverlayDelegate, name, phone, email); } } - public void onCancelButtonClicked() { + public void onShippingAddressChanged(PersonalDataManager.AutofillProfile address) { if (mNativeAssistantOverlayDelegate != 0) { - nativeOnCancelButtonClicked(mNativeAssistantOverlayDelegate); + nativeOnShippingAddressChanged(mNativeAssistantOverlayDelegate, address); + } + } + + public void onCreditCardChanged(PersonalDataManager.CreditCard card) { + if (mNativeAssistantOverlayDelegate != 0) { + nativeOnCreditCardChanged(mNativeAssistantOverlayDelegate, card); + } + } + + public void onTermsAndConditionsChanged(@AssistantTermsAndConditionsState int state) { + if (mNativeAssistantOverlayDelegate != 0) { + nativeOnTermsAndConditionsChanged(mNativeAssistantOverlayDelegate, state); } } @@ -47,11 +65,12 @@ mNativeAssistantOverlayDelegate = 0; } - private native void nativeOnGetPaymentInformation(long nativeAssistantPaymentRequestDelegate, - boolean succeed, @Nullable PersonalDataManager.CreditCard card, - @Nullable PersonalDataManager.AutofillProfile address, @Nullable String payerName, - @Nullable String payerPhone, @Nullable String payerEmail, - boolean isTermsAndConditionsAccepted); - - private native void nativeOnCancelButtonClicked(long nativeAssistantPaymentRequestDelegate); + private native void nativeOnContactInfoChanged(long nativeAssistantPaymentRequestDelegate, + @Nullable String payerName, @Nullable String payerPhone, @Nullable String payerEmail); + private native void nativeOnShippingAddressChanged(long nativeAssistantPaymentRequestDelegate, + @Nullable PersonalDataManager.AutofillProfile address); + private native void nativeOnCreditCardChanged(long nativeAssistantPaymentRequestDelegate, + @Nullable PersonalDataManager.CreditCard card); + private native void nativeOnTermsAndConditionsChanged( + long nativeAssistantPaymentRequestDelegate, int state); }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequest.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequest.java index 1c2b416..d3a52d7b 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequest.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AutofillAssistantPaymentRequest.java
@@ -12,7 +12,6 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.Callback; -import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; @@ -213,13 +212,27 @@ mWebContents.getLastCommittedUrl()), SecurityStateModel.getSecurityLevelForWebContents(mWebContents), new ShippingStrings(PaymentShippingType.SHIPPING)); - // This payment request is embedded in another flow, so update the 'Pay' button text to - // 'Confirm'. - mUI.updatePayButtonText(R.string.autofill_assistant_payment_info_confirm); mAddressEditor.setEditorDialog(mUI.getEditorDialog()); mCardEditor.setEditorDialog(mUI.getCardEditorDialog()); if (mContactEditor != null) mContactEditor.setEditorDialog(mUI.getEditorDialog()); + + // Notify initial selections. + if (mContactSection != null && mContactSection.getSelectedItem() != null) { + onSectionOptionSelected( + PaymentRequestUI.DataType.CONTACT_DETAILS, mContactSection.getSelectedItem()); + } + + if (mShippingAddressesSection != null + && mShippingAddressesSection.getSelectedItem() != null) { + onSectionOptionSelected(PaymentRequestUI.DataType.SHIPPING_ADDRESSES, + mShippingAddressesSection.getSelectedItem()); + } + + if (mPaymentMethodsSection != null && mPaymentMethodsSection.getSelectedItem() != null) { + onSectionOptionSelected(PaymentRequestUI.DataType.PAYMENT_METHODS, + mPaymentMethodsSection.getSelectedItem()); + } } private void createShippingSection( @@ -295,12 +308,13 @@ } @PaymentRequestUI.SelectionResult - public int onSectionOptionSelected(@PaymentRequestUI.DataType int optionType, - EditableOption option, Callback<PaymentInformation> checkedCallback) { + public int onSectionOptionSelected( + @PaymentRequestUI.DataType int optionType, EditableOption option) { if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) { AutofillAddress address = (AutofillAddress) option; if (address.isComplete()) { mShippingAddressesSection.setSelectedItem(option); + mDelegate.onShippingAddressChanged(address.getProfile()); } else { editAddress(address); return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH; @@ -309,6 +323,7 @@ AutofillContact contact = (AutofillContact) option; if (contact.isComplete()) { mContactSection.setSelectedItem(option); + mDelegate.onContactInfoChanged(contact); } else { editContact(contact); return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH; @@ -317,6 +332,7 @@ AutofillPaymentInstrument card = (AutofillPaymentInstrument) option; if (card.isComplete()) { mPaymentMethodsSection.setSelectedItem(option); + mDelegate.onCreditCardChanged(card.getCard()); } else { editCard(card); return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH; @@ -485,48 +501,11 @@ return networksByString; } - public boolean onPayClicked(EditableOption selectedShippingAddress, - EditableOption selectedShippingOption, EditableOption selectedPaymentMethod, - boolean isTermsAndConditionsAccepted) { - SelectedPaymentInformation selectedPaymentInformation = new SelectedPaymentInformation(); - - selectedPaymentInformation.isTermsAndConditionsAccepted = isTermsAndConditionsAccepted; - selectedPaymentInformation.card = - ((AutofillPaymentInstrument) selectedPaymentMethod).getCard(); - if (mPaymentOptions.mRequestShipping && selectedShippingAddress != null) { - selectedPaymentInformation.address = - ((AutofillAddress) selectedShippingAddress).getProfile(); - } - if (mPaymentOptions.mRequestPayerName || mPaymentOptions.mRequestPayerPhone - || mPaymentOptions.mRequestPayerEmail) { - EditableOption selectedContact = - mContactSection != null ? mContactSection.getSelectedItem() : null; - if (selectedContact != null) { - selectedPaymentInformation.payerName = - ((AutofillContact) selectedContact).getPayerName(); - selectedPaymentInformation.payerPhone = - ((AutofillContact) selectedContact).getPayerPhone(); - selectedPaymentInformation.payerEmail = - ((AutofillContact) selectedContact).getPayerEmail(); - } - } - selectedPaymentInformation.succeed = true; - mDelegate.onPaymentInformationSelected(selectedPaymentInformation); - return false; - } - - public void onDismiss() { - SelectedPaymentInformation selectedPaymentInformation = new SelectedPaymentInformation(); - selectedPaymentInformation.succeed = false; - mDelegate.onPaymentInformationSelected(selectedPaymentInformation); - close(); - } - - public void onCancelButtonClicked() { - mDelegate.onCancelButtonClicked(); - } - public void onCardAndAddressSettingsClicked() { // TODO(crbug.com/806868): Allow user to control cards and addresses. } + + public void onTermsAndConditionsChanged(@AssistantTermsAndConditionsState int state) { + mDelegate.onTermsAndConditionsChanged(state); + } }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestBottomBar.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestBottomBar.java deleted file mode 100644 index a4a0ac4..0000000 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestBottomBar.java +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2018 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.autofill_assistant.payment; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.LinearLayout; - -import org.chromium.chrome.autofill_assistant.R; - -/** Autofill Assistant specific bottom bar for the payment request UI. */ -public class PaymentRequestBottomBar extends LinearLayout { - private View mPrimaryButton; - private View mSecondaryButton; - - /** Constructor for when the PaymentRequestBottomBar is inflated from XML. */ - public PaymentRequestBottomBar(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mPrimaryButton = findViewById(R.id.button_primary); - mSecondaryButton = findViewById(R.id.button_secondary); - } -}
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestUI.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestUI.java index 72be9090..b4f5221 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestUI.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/PaymentRequestUI.java
@@ -13,7 +13,6 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.support.annotation.IntDef; import android.support.v4.view.animation.LinearOutSlowInInterpolator; import android.text.TextUtils; @@ -24,7 +23,6 @@ import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; -import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.RadioButton; @@ -58,8 +56,8 @@ * * Note: This is an Autofill Assistant specific fork of payments/ui/PaymentRequestUI.java. */ -public class PaymentRequestUI implements DialogInterface.OnDismissListener, View.OnClickListener, - PaymentRequestSection.SectionDelegate { +public class PaymentRequestUI + implements View.OnClickListener, PaymentRequestSection.SectionDelegate { @IntDef({DataType.SHIPPING_ADDRESSES, DataType.SHIPPING_OPTIONS, DataType.CONTACT_DETAILS, DataType.PAYMENT_METHODS}) @Retention(RetentionPolicy.SOURCE) @@ -106,8 +104,6 @@ private FadingEdgeScrollView mPaymentContainer; private LinearLayout mPaymentContainerLayout; - private ViewGroup mBottomBar; - private Button mPayButton; private View mSpinnyLayout; // View used to store a view to be replaced with the current payment request UI. private View mBackupView; @@ -201,7 +197,6 @@ } else { expand(null); } - updatePayButtonEnabled(); } }; @@ -270,11 +265,10 @@ result.getPaymentMethods() .getDisplaySelectedItemSummaryInSingleLineInNormalMode()); updateSection(DataType.PAYMENT_METHODS, result.getPaymentMethods()); - updatePayButtonEnabled(); // Hide the loading indicators and show the real sections. changeSpinnerVisibility(false); - mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator(false)); + mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator()); } }); } @@ -301,13 +295,6 @@ TextView messageView = (TextView) mRequestView.findViewById(R.id.message); messageView.setText(R.string.payments_loading_message); - // Set up the buttons. - mBottomBar = (ViewGroup) mRequestView.findViewById(R.id.bottom_bar); - mPayButton = (Button) mBottomBar.findViewById(R.id.button_primary); - mPayButton.setOnClickListener(this); - mBottomBar.findViewById(R.id.button_secondary) - .setOnClickListener((unusedView) -> mClient.onCancelButtonClicked()); - // Set terms & conditions text. mAcceptThirdPartyConditions = mRequestView.findViewById(R.id.terms_checkbox_agree); mReviewThirdPartyConditions = mRequestView.findViewById(R.id.terms_checkbox_review); @@ -393,9 +380,6 @@ mRequestView.addOnLayoutChangeListener(new PeekingAnimator()); - // Enabled in updatePayButtonEnabled() when the user has selected all payment options. - mPayButton.setEnabled(false); - // Force the initial appearance of edit chevrons next to all sections. updateSectionVisibility(); } @@ -424,15 +408,6 @@ } /** - * Update default text on the pay button to the given text. - * - * @param textResId The resource id of the text to be shown on the button. - */ - public void updatePayButtonText(int textResId) { - mPayButton.setText(textResId); - } - - /** * Updates the line items in response to a changed shipping address or option. * * @param cart The shopping cart, including the line items and the total. @@ -470,7 +445,6 @@ boolean isFinishingEditItem = mIsEditingPaymentItem; mIsEditingPaymentItem = false; updateSectionButtons(); - updatePayButtonEnabled(); } // Only show shipping option section once there are shipping options. @@ -500,19 +474,17 @@ if (section == mShippingAddressSection && mShippingAddressSectionInformation.getSelectedItem() != option) { mShippingAddressSectionInformation.setSelectedItem(option); - result = mClient.onSectionOptionSelected( - DataType.SHIPPING_ADDRESSES, option, mUpdateSectionsCallback); + result = mClient.onSectionOptionSelected(DataType.SHIPPING_ADDRESSES, option); } else if (section == mShippingOptionSection && mShippingOptionsSectionInformation.getSelectedItem() != option) { mShippingOptionsSectionInformation.setSelectedItem(option); - result = mClient.onSectionOptionSelected( - DataType.SHIPPING_OPTIONS, option, mUpdateSectionsCallback); + result = mClient.onSectionOptionSelected(DataType.SHIPPING_OPTIONS, option); } else if (section == mContactDetailsSection) { mContactDetailsSectionInformation.setSelectedItem(option); - result = mClient.onSectionOptionSelected(DataType.CONTACT_DETAILS, option, null); + result = mClient.onSectionOptionSelected(DataType.CONTACT_DETAILS, option); } else if (section == mPaymentMethodSection) { mPaymentMethodSectionInformation.setSelectedItem(option); - result = mClient.onSectionOptionSelected(DataType.PAYMENT_METHODS, option, null); + result = mClient.onSectionOptionSelected(DataType.PAYMENT_METHODS, option); } updateStateFromResult(section, result); @@ -573,8 +545,6 @@ } else { expand(null); } - - updatePayButtonEnabled(); } @Override @@ -620,39 +590,19 @@ expand(mContactDetailsSection); } else if (v == mPaymentMethodSection) { expand(mPaymentMethodSection); - } else if (v == mPayButton) { - processPayButton(); - } - - updatePayButtonEnabled(); - } - - private void processPayButton() { - assert !mIsShowingSpinner; - mIsProcessingPayClicked = true; - - boolean shouldShowSpinner = mClient.onPayClicked(mShippingAddressSectionInformation == null - ? null - : mShippingAddressSectionInformation.getSelectedItem(), - mShippingOptionsSectionInformation == null - ? null - : mShippingOptionsSectionInformation.getSelectedItem(), - mPaymentMethodSectionInformation.getSelectedItem(), - mAcceptThirdPartyConditions.isChecked()); - - if (shouldShowSpinner) { - changeSpinnerVisibility(true); + } else if (v == mAcceptThirdPartyConditions || v == mReviewThirdPartyConditions) { + mClient.onTermsAndConditionsChanged(getTermsAndConditionState()); } } - /** - * Called when user cancelled out of the UI that was shown after they clicked [PAY] button. - */ - public void onPayButtonProcessingCancelled() { - assert mIsProcessingPayClicked; - mIsProcessingPayClicked = false; - changeSpinnerVisibility(false); - updatePayButtonEnabled(); + private int getTermsAndConditionState() { + if (mAcceptThirdPartyConditions.isChecked()) { + return AssistantTermsAndConditionsState.ACCEPTED; + } else if (mReviewThirdPartyConditions.isChecked()) { + return AssistantTermsAndConditionsState.REQUIRES_REVIEW; + } else { + return AssistantTermsAndConditionsState.NOT_SELECTED; + } } /** @@ -681,7 +631,6 @@ if (showSpinner) { mPaymentContainer.setVisibility(View.GONE); - mBottomBar.setVisibility(View.GONE); mSpinnyLayout.setVisibility(View.VISIBLE); // Turn the bottom sheet back into a collapsed bottom sheet showing only the spinner. @@ -691,7 +640,6 @@ mRequestView.requestLayout(); } else { mPaymentContainer.setVisibility(View.VISIBLE); - mBottomBar.setVisibility(View.VISIBLE); mSpinnyLayout.setVisibility(View.GONE); if (mIsExpandedToFullHeight) { @@ -702,25 +650,6 @@ } } - private void updatePayButtonEnabled() { - boolean contactInfoOk = !mRequestContactDetails - || (mContactDetailsSectionInformation != null - && mContactDetailsSectionInformation.getSelectedItem() != null); - boolean shippingInfoOk = !mRequestShipping - || (mShippingAddressSectionInformation != null - && mShippingAddressSectionInformation.getSelectedItem() != null); - boolean shippingOptionInfoOk = !mRequestShippingOption - || (mShippingOptionsSectionInformation != null - && mShippingOptionsSectionInformation.getSelectedItem() != null); - boolean termsOptionOk = - mAcceptThirdPartyConditions.isChecked() || mReviewThirdPartyConditions.isChecked(); - mPayButton.setEnabled(contactInfoOk && shippingInfoOk && shippingOptionInfoOk - && mPaymentMethodSectionInformation != null - && mPaymentMethodSectionInformation.getSelectedItem() != null - && !mIsClientCheckingSelection && !mIsEditingPaymentItem && !mIsClosing - && termsOptionOk); - } - /** @return Whether or not the dialog can be closed via the X close button. */ private boolean isAcceptingCloseButton() { return mSheetAnimator == null && mSectionAnimator == null && !mIsProcessingPayClicked @@ -748,7 +677,7 @@ if (!mIsExpandedToFullHeight && section != null) { // Container now takes the full height of the screen, animating towards it. mRequestView.getLayoutParams().height = LayoutParams.MATCH_PARENT; - mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator(true)); + mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator()); mPaymentContainerLayout.requestLayout(); // Disable all but the first button. @@ -823,32 +752,6 @@ } } - /** - * Called when the dialog is dismissed. Can be caused by: - * <ul> - * <li>User click on the "back" button on the phone.</li> - * <li>User click on the "X" button in the top-right corner of the dialog.</li> - * <li>User click on the "CANCEL" button on the bottom of the dialog.</li> - * <li>Successfully processing the payment.</li> - * <li>Failure to process the payment.</li> - * <li>The JavaScript calling the abort() method in PaymentRequest API.</li> - * <li>The PaymentRequest JavaScript object being destroyed.</li> - * <li>User closing all incognito windows with PaymentRequest UI open in an incognito - * window.</li> - * </ul> - */ - @Override - public void onDismiss(DialogInterface dialog) { - dismiss(); - } - - private void dismiss() { - mIsClosing = true; - if (mEditorDialog.isShowing()) mEditorDialog.dismiss(); - if (mCardEditorDialog.isShowing()) mCardEditorDialog.dismiss(); - mClient.onDismiss(); - } - @Override public String getAdditionalText(PaymentRequestSection section) { if (section == mShippingAddressSection) { @@ -930,12 +833,9 @@ /** Animates the bottom sheet expanding to a larger sheet. */ private class SheetEnlargingAnimator extends AnimatorListenerAdapter implements OnLayoutChangeListener { - private final boolean mIsBottomBarLockedInPlace; private int mContainerHeightDifference; - public SheetEnlargingAnimator(boolean isBottomBarLockedInPlace) { - mIsBottomBarLockedInPlace = isBottomBarLockedInPlace; - } + public SheetEnlargingAnimator() {} /** * Updates the animation. @@ -947,20 +847,6 @@ // the translation until it is in the right place on screen. float containerTranslation = mContainerHeightDifference * progress; mRequestView.setTranslationY(containerTranslation); - - if (mIsBottomBarLockedInPlace) { - // The bottom bar is translated along the dialog so that is looks like it stays in - // place at the bottom while the entire bottom sheet is translating upwards. - mBottomBar.setTranslationY(-containerTranslation); - - // The payment container is sandwiched between the header and the bottom bar. - // Expansion animates by changing where its "bottom" is, letting its shadows appear - // and disappear as it changes size. - int paymentContainerBottom = - Math.min(mPaymentContainer.getTop() + mPaymentContainer.getMeasuredHeight(), - mBottomBar.getTop()); - mPaymentContainer.setBottom(paymentContainerBottom); - } } @Override @@ -991,7 +877,6 @@ public void onAnimationEnd(Animator animation) { // Reset the layout so that everything is in the expected place. mRequestView.setTranslationY(0); - mBottomBar.setTranslationY(0); mRequestView.requestLayout(); // Indicate that the dialog is ready to use.
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd index 4e19a82c..72fd9b0 100644 --- a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd +++ b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
@@ -133,9 +133,6 @@ <message name="IDS_AUTOFILL_ASSISTANT_FIRST_RUN_ACCESSIBILITY" desc="Accessibility description of Autofill Assistant first run screen is shown."> Google Assistant in Chrome first run screen is shown </message> - <message name="IDS_AUTOFILL_ASSISTANT_PAYMENT_INFO_CONFIRM" desc="Text on the payment request primary button to confirm payment information [CHAR-LIMIT=32]"> - Continue - </message> <message name="IDS_AUTOFILL_ASSISTANT_GIVE_UP" desc="Text label that is shown when autofill assistant cannot help anymore, because of a user action." internal_comment="TODO(wnwen): Remove duplication in components/autofill_assistant_strings.grdp">
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java index 11df2137..5a124d4 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -180,10 +180,11 @@ private void testChips(InOrder inOrder, AssistantCarouselModel carouselModel, AssistantCarouselCoordinator carouselCoordinator) { - List<AssistantChip> chips = Arrays.asList( - new AssistantChip( - AssistantChip.Type.CHIP_ASSISTIVE, "chip 0", () -> {/* do nothing */}), - new AssistantChip(AssistantChip.Type.CHIP_ASSISTIVE, "chip 1", mRunnableMock)); + List<AssistantChip> chips = + Arrays.asList(new AssistantChip(AssistantChip.Type.CHIP_ASSISTIVE, "chip 0", + /* disabled= */ false, () -> {/* do nothing */}), + new AssistantChip(AssistantChip.Type.CHIP_ASSISTIVE, "chip 1", + /* disabled= */ false, mRunnableMock)); ThreadUtils.runOnUiThreadBlocking(() -> carouselModel.getChipsModel().set(chips)); RecyclerView chipsViewContainer = carouselCoordinator.getView(); Assert.assertEquals(2, chipsViewContainer.getAdapter().getItemCount());
diff --git a/chrome/android/features/touchless/BUILD.gn b/chrome/android/features/touchless/BUILD.gn deleted file mode 100644 index b7a485f..0000000 --- a/chrome/android/features/touchless/BUILD.gn +++ /dev/null
@@ -1,41 +0,0 @@ -# Copyright 2019 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("//build/config/android/config.gni") -import("//build/config/android/rules.gni") - -android_library("java") { - java_files = - [ "java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java" ] - - deps = [ - "//base:base_java", - "//chrome/android:chrome_java", - "//content/public/android:content_java", - "//ui/android:ui_java", - ] -} - -android_library("touchless_java_test") { - testonly = true - - java_files = [ "javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java" ] - - deps = [ - ":java", - "//base:base_java", - "//base:base_java_test_support", - "//chrome/android:browser_java_test_support", - "//chrome/android:chrome_java", - "//chrome/android:chrome_test_java", - "//chrome/android:chrome_test_util_java", - "//chrome/test/android:chrome_java_test_support", - "//components/safe_browsing/android:safe_browsing_java", - "//content/public/android:content_java", - "//content/public/test/android:content_java_test_support", - "//net/android:net_java_test_support", - "//third_party/android_support_test_runner:runner_java", - "//third_party/junit:junit", - ] -}
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java index 6f1e7da..359094a 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
@@ -228,32 +228,38 @@ @Override public void onInternalError(@InternalFeedError int internalError) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnInternalError(mNativeFeedLoggingBridge, internalError); } @Override public void onTokenCompleted(boolean wasSynthetic, int contentCount, int tokenCount) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnTokenCompleted(mNativeFeedLoggingBridge, wasSynthetic, contentCount, tokenCount); } @Override public void onTokenFailedToComplete(boolean wasSynthetic, int failureCount) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnTokenFailedToComplete(mNativeFeedLoggingBridge, wasSynthetic, failureCount); } @Override public void onServerRequest(@RequestReason int requestReason) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnServerRequest(mNativeFeedLoggingBridge, requestReason); } @Override public void onZeroStateShown(@ZeroStateShowReason int zeroStateShowReason) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnZeroStateShown(mNativeFeedLoggingBridge, zeroStateShowReason); } @Override public void onZeroStateRefreshCompleted(int newContentCount, int newTokenCount) { - // TODO(https://crbug.com/924739): Implementation. + if (mNativeFeedLoggingBridge == 0) return; + nativeOnZeroStateRefreshCompleted(mNativeFeedLoggingBridge, newContentCount, newTokenCount); } @Override @@ -377,6 +383,16 @@ long nativeFeedLoggingBridge, long spinnerShownTimeMs, int spinnerType); private native void nativeOnPietFrameRenderingEvent( long nativeFeedLoggingBridge, int[] pietErrorCodes); + private native void nativeOnInternalError(long nativeFeedLoggingBridge, int internalError); + private native void nativeOnTokenCompleted( + long nativeFeedLoggingBridge, boolean wasSynthetic, int contentCount, int tokenCount); + private native void nativeOnTokenFailedToComplete( + long nativeFeedLoggingBridge, boolean wasSynthetic, int failureCount); + private native void nativeOnServerRequest(long nativeFeedLoggingBridge, int requestReason); + private native void nativeOnZeroStateShown( + long nativeFeedLoggingBridge, int zeroStateShowReason); + private native void nativeOnZeroStateRefreshCompleted( + long nativeFeedLoggingBridge, int newContentCount, int newTokenCount); private native void nativeOnContentTargetVisited( long nativeFeedLoggingBridge, long visitTimeMs, boolean isOffline, boolean returnToNtp); private native void nativeReportScrolledAfterOpen(long nativeFeedLoggingBridge);
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index e21cba7a..91dba26 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -545,6 +545,8 @@ {{ self.chrome_activity_common() }}> {{ self.extra_web_rendering_activity_definitions() }} </activity> + {% set notouch_build = notouch_build|default(0) %} + {% if notouch_build == "true" %} <activity android:name="org.chromium.chrome.browser.touchless.NoTouchActivity" android:theme="@style/Theme.Chromium.Activity" android:exported="false" @@ -553,6 +555,7 @@ {{ self.supports_video_persistence() }} > {{ self.extra_web_rendering_activity_definitions() }} </activity> + {% endif %} <activity android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity" android:theme="@style/Theme.Chromium.Activity"
diff --git a/chrome/android/java/README.md b/chrome/android/java/README.md index 51d6ca0..c14b8eb3d 100644 --- a/chrome/android/java/README.md +++ b/chrome/android/java/README.md
@@ -63,17 +63,31 @@ ### Fixing build failures -1. Ensure your args.gn contains these args: -``` -enable_chrome_android_internal = false -is_java_debug = false -``` +1. Ensure that: + + * Your args.gn contains these args: + + ``` + enable_chrome_android_internal = false + is_java_debug = false + ``` + + * Your local branch is up-to-date with master + 2. Run: -``` -autoninja -C $CHROMIUM_OUTPUT_DIR monochrome_public_apk -``` + For AndroidManifest failures: + + ``` + autoninja -C $CHROMIUM_OUTPUT_DIR monochrome_public_apk__merge_manifests + ``` + + For Proguard flags failures: + + ``` + autoninja -C $CHROMIUM_OUTPUT_DIR monochrome_public_apk + ``` 3. Run the command suggested in the error message to copy the contents of the generated file to the expected file path
diff --git a/chrome/android/java/monochrome_public_apk.AndroidManifest.expected b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected index 6aeba47..c522db1c 100644 --- a/chrome/android/java/monochrome_public_apk.AndroidManifest.expected +++ b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected
@@ -816,16 +816,6 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" android:exported="false" android:hardwareAccelerated="false" - android:launchMode="singleTask" - android:name="org.chromium.chrome.browser.touchless.NoTouchActivity" - android:resizeableActivity="true" - android:supportsPictureInPicture="true" - android:theme="@style/Theme.Chromium.Activity" - android:windowSoftInputMode="adjustResize"/> - <activity - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" - android:exported="false" - android:hardwareAccelerated="false" android:name="org.chromium.chrome.browser.customtabs.CustomTabActivity" android:resizeableActivity="true" android:supportsPictureInPicture="true"
diff --git a/chrome/android/java/res/layout/bottom_tab_strip_toolbar.xml b/chrome/android/java/res/layout/bottom_tab_strip_toolbar.xml index f682754..01d8599 100644 --- a/chrome/android/java/res/layout/bottom_tab_strip_toolbar.xml +++ b/chrome/android/java/res/layout/bottom_tab_strip_toolbar.xml
@@ -11,7 +11,7 @@ <LinearLayout android:id="@+id/main_content" android:layout_width="match_parent" - android:layout_height="@dimen/bottom_sheet_peek_height" + android:layout_height="match_parent" android:orientation="horizontal" android:gravity="center_vertical" android:background="@color/modern_primary_color">
diff --git a/chrome/android/java/res/layout/omnibox_answer_suggestion.xml b/chrome/android/java/res/layout/omnibox_answer_suggestion.xml index ac24dbff..ee2b403b 100644 --- a/chrome/android/java/res/layout/omnibox_answer_suggestion.xml +++ b/chrome/android/java/res/layout/omnibox_answer_suggestion.xml
@@ -60,7 +60,7 @@ <ImageView android:background="?attr/selectableItemBackground" android:clickable="true" - android:contentDescription="@null" + android:contentDescription="@string/accessibility_omnibox_btn_refine" android:focusable="true" android:id="@id/omnibox_answer_refine_icon" android:layout_alignBottom="@id/omnibox_answer"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 52afb27..0d8ebcc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1469,21 +1469,11 @@ // Create after native initialization so subclasses that override this method have a chance // to setup. mPageViewTimer = createPageViewTimer(); - - if (shouldInitializeBottomSheet()) { - ViewGroup coordinator = findViewById(R.id.coordinator); - getLayoutInflater().inflate(R.layout.bottom_sheet, coordinator); - mBottomSheet = coordinator.findViewById(R.id.bottom_sheet); - mBottomSheet.init(coordinator, this); - - ((BottomContainer) findViewById(R.id.bottom_container)).setBottomSheet(mBottomSheet); - - mBottomSheetController = new BottomSheetController(this, mActivityTabProvider, - mScrimView, mBottomSheet, - getCompositorViewHolder().getLayoutManager().getOverlayPanelManager(), + if (shouldInitializeBottomSheet() + && FeatureUtilities.areContextualSuggestionsEnabled(this)) { + initializeBottomSheet( !ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_BUTTON)); - - mComponent.resolveContextualSuggestionsCoordinator(); + getComponent().resolveContextualSuggestionsCoordinator(); } } @@ -1495,6 +1485,24 @@ } /** + * Initializes the {@link BottomSheet} and {@link BottomSheetController} for use. + * @param suppressSheetForContextualSearch Whether the sheet should be suppressed when + * Contextual search is showing. + */ + protected void initializeBottomSheet(boolean suppressSheetForContextualSearch) { + ViewGroup coordinator = findViewById(R.id.coordinator); + getLayoutInflater().inflate(R.layout.bottom_sheet, coordinator); + mBottomSheet = coordinator.findViewById(R.id.bottom_sheet); + mBottomSheet.init(coordinator, this); + + ((BottomContainer) findViewById(R.id.bottom_container)).setBottomSheet(mBottomSheet); + + mBottomSheetController = new BottomSheetController(this, mActivityTabProvider, mScrimView, + mBottomSheet, getCompositorViewHolder().getLayoutManager().getOverlayPanelManager(), + suppressSheetForContextualSearch); + } + + /** * @return Whether native initialization has been completed for this activity. */ public boolean didFinishNativeInitialization() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 5f1f5a0a..0b66e5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -972,6 +972,10 @@ }; OnClickListener bookmarkClickHandler = v -> addOrEditBookmark(getActivityTab()); + if (shouldInitializeBottomSheet() && FeatureUtilities.isTabGroupsAndroidEnabled()) { + initializeBottomSheet(false); + } + getToolbarManager().initializeWithNative(mTabModelSelectorImpl, getFullscreenManager().getBrowserVisibilityDelegate(), getFindToolbarManager(), mOverviewModeController, mLayoutManager, tabSwitcherClickHandler, @@ -1580,7 +1584,9 @@ @Override protected void initializeToolbar() { super.initializeToolbar(); - if (!isTablet() && FeatureUtilities.isBottomToolbarEnabled()) { + if (!isTablet() + && (FeatureUtilities.isBottomToolbarEnabled() + || FeatureUtilities.isTabGroupsAndroidEnabled())) { getToolbarManager().enableBottomToolbar(); } } @@ -2584,7 +2590,8 @@ @Override protected boolean shouldInitializeBottomSheet() { - return FeatureUtilities.areContextualSuggestionsEnabled(this); + return FeatureUtilities.areContextualSuggestionsEnabled(this) + || FeatureUtilities.isTabGroupsAndroidEnabled(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 0ebec871..ae2c6f2d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -691,6 +691,7 @@ Point viewportSize = getViewportSize(); setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, viewportSize.y); + onViewportChanged(); } @Override @@ -699,6 +700,7 @@ Point viewportSize = getViewportSize(); setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, viewportSize.y); + onViewportChanged(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimationHandler.java index ab913f8..887b8357 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimationHandler.java
@@ -149,4 +149,13 @@ public static boolean isInTestingMode() { return sIsInTestingMode; } + + /** + * Provides update for animation in testing mode. + * @return Whether update was successful or not. + */ + @VisibleForTesting + public final boolean pushUpdateInTestingMode(long deltaTimeMs) { + return sIsInTestingMode ? pushUpdate(deltaTimeMs) : false; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java index 205ca3e..7071f3f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -6,10 +6,12 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.content.Context; import android.content.res.Resources; import android.graphics.RectF; import android.support.annotation.IntDef; +import android.util.Pair; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; @@ -17,6 +19,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; +import org.chromium.chrome.browser.compositor.animation.FloatProperty; import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation; import org.chromium.chrome.browser.compositor.layouts.Layout; import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation; @@ -32,6 +35,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Iterator; /** * Handles all the drawing and events of a stack of stackTabs. @@ -222,6 +227,7 @@ // Running set of animations applied to tabs. private ChromeAnimation<?> mTabAnimations; + private Pair<AnimatorSet, ArrayList<FloatProperty>> mAnimatorSetTabAnimations; private Animator mViewAnimations; // The parent Layout @@ -541,17 +547,23 @@ // Build the AnimatorSet using the TabSwitcherAnimationFactory. // This will give us the appropriate AnimatorSet based on the current // state of the tab switcher and the OverviewAnimationType specified. - mTabAnimations = mAnimationFactory.createAnimatorSetForType(type, this, mStackTabs, - focusIndex, sourceIndex, mSpacing, getDiscardRange()); + mTabAnimations = mAnimationFactory.createChromeAnimationSetForType(type, this, + mStackTabs, focusIndex, sourceIndex, mSpacing, getDiscardRange()); + mAnimatorSetTabAnimations = mAnimationFactory.createAnimatorSetForType(type, this, + mStackTabs, focusIndex, sourceIndex, mSpacing, getDiscardRange()); } if (mTabAnimations != null) mTabAnimations.start(); + if (mAnimatorSetTabAnimations != null) mAnimatorSetTabAnimations.first.start(); if (mViewAnimations != null) mViewAnimations.start(); - if (mTabAnimations != null || mViewAnimations != null) { + if (mTabAnimations != null || mAnimatorSetTabAnimations != null + || mViewAnimations != null) { mLayout.onStackAnimationStarted(); } - if ((mTabAnimations == null && mViewAnimations == null) || finishImmediately) { + if ((mTabAnimations == null && mAnimatorSetTabAnimations == null + && mViewAnimations == null) + || finishImmediately) { finishAnimation(time); } } @@ -566,8 +578,12 @@ */ protected void finishAnimation(long time) { if (mTabAnimations != null) mTabAnimations.updateAndFinish(); + if (mAnimatorSetTabAnimations != null) mAnimatorSetTabAnimations.first.end(); if (mViewAnimations != null) mViewAnimations.end(); - if (mTabAnimations != null || mViewAnimations != null) mLayout.onStackAnimationFinished(); + if (mTabAnimations != null || mAnimatorSetTabAnimations != null + || mViewAnimations != null) { + mLayout.onStackAnimationFinished(); + } switch (mOverviewAnimationType) { case OverviewAnimationType.ENTER_STACK: @@ -621,6 +637,7 @@ mOverviewAnimationType = OverviewAnimationType.NONE; mTabAnimations = null; + mAnimatorSetTabAnimations = null; mViewAnimations = null; } @@ -685,8 +702,8 @@ || mOverviewAnimationType == OverviewAnimationType.UNDISCARD || mOverviewAnimationType == OverviewAnimationType.DISCARD_ALL) && (type == OverviewAnimationType.DISCARD - || type == OverviewAnimationType.UNDISCARD - || type == OverviewAnimationType.DISCARD_ALL)) { + || type == OverviewAnimationType.UNDISCARD + || type == OverviewAnimationType.DISCARD_ALL)) { return true; } } @@ -702,6 +719,17 @@ || mOverviewAnimationType == OverviewAnimationType.UNDISCARD || mOverviewAnimationType == OverviewAnimationType.DISCARD_ALL) { mTabAnimations.cancel(null, StackTab.Property.SCROLL_OFFSET); + if (mAnimatorSetTabAnimations != null) { + Iterator<FloatProperty> propertyIterator = + mAnimatorSetTabAnimations.second.iterator(); + Iterator<Animator> animatorIterator = + mAnimatorSetTabAnimations.first.getChildAnimations().iterator(); + + while (animatorIterator.hasNext()) { + CompositorAnimator a = (CompositorAnimator) animatorIterator.next(); + if (propertyIterator.next() == StackTab.SCROLL_OFFSET) a.cancel(); + } + } return true; } return false; @@ -731,30 +759,45 @@ public boolean onUpdateCompositorAnimations(long time, boolean jumpToEnd) { if (!jumpToEnd) updateScrollOffset(time); - boolean finished = true; + boolean animatorSetFinished = true; + boolean chromeAnimationsFinished = true; if (mTabAnimations != null) { if (jumpToEnd) { - finished = mTabAnimations.finished(); + chromeAnimationsFinished = mTabAnimations.finished(); } else { - finished = mTabAnimations.update(time); + chromeAnimationsFinished = mTabAnimations.update(time); } + } + if (mAnimatorSetTabAnimations != null) { + animatorSetFinished = jumpToEnd ? true : !mAnimatorSetTabAnimations.first.isRunning(); + } + if (mTabAnimations != null || mAnimatorSetTabAnimations != null) { finishAnimationsIfDone(time, jumpToEnd); } if (jumpToEnd) forceScrollStop(); - return finished; + return chromeAnimationsFinished || animatorSetFinished; } private void finishAnimationsIfDone(long time, boolean jumpToEnd) { boolean hasViewAnimations = mViewAnimations != null; - boolean hasTabAnimations = mTabAnimations != null; - boolean hasAnimations = hasViewAnimations || hasTabAnimations; boolean isViewFinished = hasViewAnimations ? !mViewAnimations.isRunning() : true; + + boolean hasTabAnimations = mTabAnimations != null; boolean isTabFinished = hasTabAnimations ? mTabAnimations.finished() : true; + boolean hasAnimatorSetTabAnimations = mAnimatorSetTabAnimations != null; + boolean isAnimatorSetTabFinished = + hasAnimatorSetTabAnimations ? !mAnimatorSetTabAnimations.first.isRunning() : true; + + boolean hasAnimations = + hasViewAnimations || hasTabAnimations || hasAnimatorSetTabAnimations; + boolean shouldFinish = jumpToEnd && hasAnimations; shouldFinish |= hasAnimations && (!hasViewAnimations || isViewFinished) - && (!hasTabAnimations || isTabFinished); + && (!hasTabAnimations || isTabFinished) + && (!hasAnimatorSetTabAnimations || isAnimatorSetTabFinished); + if (shouldFinish) finishAnimation(time); } @@ -846,9 +889,9 @@ private void discard(float x, float y, float amountX, float amountY) { if (mStackTabs == null || (mOverviewAnimationType != OverviewAnimationType.NONE - && mOverviewAnimationType != OverviewAnimationType.DISCARD - && mOverviewAnimationType != OverviewAnimationType.DISCARD_ALL - && mOverviewAnimationType != OverviewAnimationType.UNDISCARD)) { + && mOverviewAnimationType != OverviewAnimationType.DISCARD + && mOverviewAnimationType != OverviewAnimationType.DISCARD_ALL + && mOverviewAnimationType != OverviewAnimationType.UNDISCARD)) { return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java index 36f389db..0f583bd4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java
@@ -6,11 +6,14 @@ import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.addAnimation; +import android.animation.AnimatorSet; import android.support.annotation.IntDef; +import android.util.Pair; import android.view.animation.Interpolator; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; +import org.chromium.chrome.browser.compositor.animation.FloatProperty; import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation; import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable; import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation; @@ -19,6 +22,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; /** * A factory that builds animations for the tab stack. @@ -165,8 +169,9 @@ * @param discardRange The range of the discard amount value. * @return The resulting TabSwitcherAnimation that will animate the tabs. */ - public ChromeAnimation<?> createAnimatorSetForType(@OverviewAnimationType int type, Stack stack, - StackTab[] tabs, int focusIndex, int sourceIndex, int spacing, float discardRange) { + public ChromeAnimation<?> createChromeAnimationSetForType(@OverviewAnimationType int type, + Stack stack, StackTab[] tabs, int focusIndex, int sourceIndex, int spacing, + float discardRange) { if (tabs == null) return null; switch (type) { case OverviewAnimationType.ENTER_STACK: @@ -194,6 +199,27 @@ } } + /** + * The wrapper method responsible for delegating the animations request to the appropriate + * helper method. Not all parameters are used for each request. + * + * @param type The type of animation to be created. This is what + * determines which helper method is called. + * @param stack The current stack. + * @param tabs The tabs that make up the current stack that will + * be animated. + * @param focusIndex The index of the tab that is the focus of this animation. + * @param sourceIndex The index of the tab that triggered this animation. + * @param spacing The default spacing between the tabs. + * @param discardRange The range of the discard amount value. + * @return The resulting TabSwitcherAnimation that will animate the tabs. + */ + public Pair<AnimatorSet, ArrayList<FloatProperty>> createAnimatorSetForType( + @OverviewAnimationType int type, Stack stack, StackTab[] tabs, int focusIndex, + int sourceIndex, int spacing, float discardRange) { + return null; + } + protected abstract float getScreenSizeInScrollDirection(); protected abstract float getScreenPositionInScrollDirection(StackTab tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index f5410e48..3e3be8f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -490,7 +490,7 @@ mTranslateController.cacheNativeTranslateData(); } else if (!TextUtils.isEmpty(selection)) { boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(); - mSearchRequest = new ContextualSearchRequest(selection, null, null, shouldPrefetch); + mSearchRequest = new ContextualSearchRequest(selection, shouldPrefetch); mTranslateController.forceAutoDetectTranslateUnlessDisabled(mSearchRequest); mDidStartLoadingResolvedSearchRequest = false; mSearchPanel.setSearchTerm(selection); @@ -680,6 +680,8 @@ * @param quickActionCategory The {@link QuickActionCategory} for the quick action. * @param loggedEventId The EventID logged by the server, which should be recorded and sent back * to the server along with user action results in a subsequent request. + * @param searchUrlFull The URL for the full search to present in the overlay, or empty. + * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. */ @CalledByNative public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, @@ -687,11 +689,11 @@ final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, final String caption, final String quickActionUri, final int quickActionCategory, - final long loggedEventId) { + final long loggedEventId, final String searchUrlFull, final String searchUrlPreload) { mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, - quickActionCategory, loggedEventId); + quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload); } @Override @@ -699,7 +701,8 @@ String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, - int quickActionCategory, long loggedEventId) { + int quickActionCategory, long loggedEventId, String searchUrlFull, + String searchUrlPreload) { if (!mInternalStateController.isStillWorkingOn(InternalState.RESOLVING)) return; // Show an appropriate message for what to search for. @@ -765,8 +768,8 @@ // TODO(donnd): Instead of preloading, we should prefetch (ie the URL should not // appear in the user's history until the user views it). See crbug.com/406446. boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchSearchResult(); - mSearchRequest = - new ContextualSearchRequest(searchTerm, alternateTerm, mid, shouldPreload); + mSearchRequest = new ContextualSearchRequest( + searchTerm, alternateTerm, mid, shouldPreload, searchUrlFull, searchUrlPreload); // Trigger translation, if enabled. mTranslateController.forceTranslateIfNeeded(mSearchRequest, contextLanguage); mDidStartLoadingResolvedSearchRequest = false; @@ -1045,8 +1048,8 @@ // is in progress or we should do a verbatim search now. if (mSearchRequest == null && mPolicy.shouldCreateVerbatimRequest() && !TextUtils.isEmpty(mSelectionController.getSelectedText())) { - mSearchRequest = new ContextualSearchRequest( - mSelectionController.getSelectedText(), null, null, false); + mSearchRequest = + new ContextualSearchRequest(mSelectionController.getSelectedText()); mDidStartLoadingResolvedSearchRequest = false; } if (mSearchRequest != null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java index 880b84a..72013609 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
@@ -41,12 +41,15 @@ * @param quickActionCategory The {@link QuickActionCategory} for the quick action. * @param loggedEventId The EventID logged by the server, which should be recorded and sent back * to the server along with user action results in a subsequent request. + * @param searchUrlFull The URL for the full search to present in the overlay, or empty. + * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. */ void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, - int quickActionCategory, long loggedEventId); + int quickActionCategory, long loggedEventId, String searchUrlFull, + String searchUrlPreload); /** * @return Whether the device is currently online.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java index 088dc04..2cfd110a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -10,6 +10,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.search_engines.TemplateUrlService; +import org.chromium.chrome.browser.util.UrlUtilities; import java.net.MalformedURLException; import java.net.URL; @@ -27,6 +28,7 @@ private boolean mIsLowPriority; private boolean mHasFailedLowPriorityLoad; private boolean mIsTranslationForced; + private boolean mIsFullSearchUrlProvided; private static final String GWS_LOW_PRIORITY_SEARCH_PATH = "s"; private static final String GWS_SEARCH_NO_SUGGESTIONS_PARAM = "sns"; @@ -49,26 +51,48 @@ * @param searchTerm The resolved search term. */ ContextualSearchRequest(String searchTerm) { - this(searchTerm, null, null, false); + this(searchTerm, false); } /** - * Creates a search request for the given search term with the given alternate term and - * low-priority loading capability. + * Creates a search request for the given search term without any alternate term and + * for low-priority loading capability if specified in the second parameter. + * @param searchTerm The resolved search term. + * @param isLowPriorityEnabled Whether the request can be made at a low priority. + */ + ContextualSearchRequest(String searchTerm, boolean isLowPriorityEnabled) { + this(searchTerm, null, null, isLowPriorityEnabled, null, null); + } + + /** + * Creates a search request for the given search term, unless the full search URL is provided + * in the {@code searchUrlFull}. When the full URL is not provided the request also uses the + * given alternate term, mid, and low-priority loading capability. <p> + * If the {@code searchUrlPreload} is provided then the {@code searchUrlFull} should also be + * provided. * @param searchTerm The resolved search term. * @param alternateTerm The alternate search term. * @param mid The MID for an entity to use to trigger a Knowledge Panel, or an empty string. * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param isLowPriorityEnabled Whether the request can be made at a low priority. + * @param searchUrlFull The URL for the full search to present in the overlay, or empty. + * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. */ ContextualSearchRequest(String searchTerm, @Nullable String alternateTerm, @Nullable String mid, - boolean isLowPriorityEnabled) { + boolean isLowPriorityEnabled, @Nullable String searchUrlFull, + @Nullable String searchUrlPreload) { mWasPrefetch = isLowPriorityEnabled; - mNormalPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, false); + mIsFullSearchUrlProvided = isGoogleUrl(searchUrlFull); + mNormalPriorityUri = mIsFullSearchUrlProvided + ? Uri.parse(searchUrlFull) + : getUriTemplate(searchTerm, alternateTerm, mid, false); if (isLowPriorityEnabled) { - // TODO(donnd): Call TemplateURL once we have an API for 3rd-party providers. - Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, true); - mLowPriorityUri = makeLowPriorityUri(baseLowPriorityUri); + if (isGoogleUrl(searchUrlPreload)) { + mLowPriorityUri = Uri.parse(searchUrlPreload); + } else { + Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, true); + mLowPriorityUri = makeLowPriorityUri(baseLowPriorityUri); + } } else { mLowPriorityUri = null; } @@ -140,8 +164,8 @@ URL url; try { - url = new URL(searchUrl.replaceAll(CTXS_PARAM_PATTERN, CTXR_PARAM) - .replaceAll(PF_PARAM, "")); + url = new URL( + searchUrl.replaceAll(CTXS_PARAM_PATTERN, CTXR_PARAM).replaceAll(PF_PARAM, "")); } catch (MalformedURLException e) { url = null; } @@ -156,6 +180,9 @@ */ void forceTranslation(String sourceLanguage, String targetLanguage) { mIsTranslationForced = true; + // If the server is providing a full URL then we shouldn't alter it. + if (mIsFullSearchUrlProvided) return; + if (mLowPriorityUri != null) { mLowPriorityUri = makeTranslateUri(mLowPriorityUri, sourceLanguage, targetLanguage); } @@ -172,7 +199,7 @@ } /** - * @return Whether translation was forced for this request. + * @return Whether translation was forced for this request (for testing only). */ @VisibleForTesting boolean isTranslationForced() { @@ -200,6 +227,16 @@ } /** + * Judges if the given URL looks like a Google URL. + * @param someUrl A URL to judge. + * @return Whether it's pointing to Google infrastructure or not. + */ + @VisibleForTesting + boolean isGoogleUrl(@Nullable String someUrl) { + return !TextUtils.isEmpty(someUrl) && UrlUtilities.nativeIsGoogleDomainUrl(someUrl, true); + } + + /** * @return a low-priority {@code Uri} from the given base {@code Uri}. */ private Uri makeLowPriorityUri(Uri baseUri) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java index 2986804..2d0879b0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -33,6 +33,7 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.chrome.browser.ChromeApplication; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.download.DownloadNotificationUmaHelper.UmaDownloadResumption; import org.chromium.chrome.browser.download.items.OfflineContentAggregatorNotificationBridgeUiFactory; import org.chromium.chrome.browser.init.BrowserParts; @@ -312,7 +313,9 @@ * @return delegate for interactions with the entry */ static DownloadServiceDelegate getServiceDelegate(ContentId id) { - if (LegacyHelpers.isLegacyDownload(id)) { + if (LegacyHelpers.isLegacyDownload(id) + && !ChromeFeatureList.isEnabled( + ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) { return DownloadManagerService.getDownloadManagerService(); } return OfflineContentAggregatorNotificationBridgeUiFactory.instance();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java index 764e012..cb70925 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
@@ -20,6 +20,7 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.util.FeatureUtilities; @@ -70,7 +71,9 @@ private static DownloadNotificationService sDownloadNotificationService; public static void setDownloadNotificationService(DownloadNotificationService service) { - sDownloadNotificationService = service; + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) { + sDownloadNotificationService = service; + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java index 4c8b00f..e5d898f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java
@@ -221,6 +221,7 @@ } } + private final boolean mUseNewDownloadPath; private final boolean mIsIncognito; private final Handler mHandler = new Handler(); private final DownloadProgressInfoBar.Client mClient = new DownloadProgressInfoBarClient(); @@ -258,6 +259,8 @@ /** Constructor. */ public DownloadInfoBarController(boolean isIncognito) { + mUseNewDownloadPath = + ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER); mIsIncognito = isIncognito; mHandler.post(() -> getOfflineContentProvider().addObserver(this)); } @@ -273,6 +276,8 @@ /** Updates the InfoBar when new information about a download comes in. */ public void onDownloadItemUpdated(DownloadItem downloadItem) { + if (mUseNewDownloadPath) return; + OfflineItem offlineItem = DownloadInfo.createOfflineItem(downloadItem.getDownloadInfo()); if (!isVisibleToUser(offlineItem)) return; @@ -291,6 +296,7 @@ /** Updates the InfoBar after a download has been removed. */ public void onDownloadItemRemoved(ContentId contentId) { + if (mUseNewDownloadPath) return; onItemRemoved(contentId); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java index c200116..0dbba8fa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java
@@ -13,8 +13,10 @@ import android.os.Environment; import android.support.v4.app.NotificationManagerCompat; import android.text.TextUtils; +import android.util.Pair; import org.chromium.base.Callback; +import org.chromium.base.ContentUriUtils; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.StrictModeContext; @@ -262,20 +264,35 @@ return ContextUtils.getApplicationContext(); } + /** + * This function is meant to be called as the last step of a download. It will add the download + * to the android's DownloadManager and determine if the download can be resolved to any + * activity so that it can be auto-opened. + */ @CalledByNative - private static void addCompletedDownload(String fileName, String description, String mimeType, - String filePath, long fileSizeBytes, String originalUrl, String referrer, - String downloadGuid, long callbackId) { - AsyncTask<Long> task = new AsyncTask<Long>() { + private static void addCompletedDownload(String fileName, String description, + String originalMimeType, String filePath, long fileSizeBytes, String originalUrl, + String referrer, String downloadGuid, long callbackId) { + final String mimeType = ChromeDownloadDelegate.remapGenericMimeType( + originalMimeType, originalUrl, fileName); + AsyncTask<Pair<Long, Boolean>> task = new AsyncTask<Pair<Long, Boolean>>() { @Override - protected Long doInBackground() { - return addCompletedDownload(fileName, description, mimeType, filePath, - fileSizeBytes, originalUrl, referrer, downloadGuid); + protected Pair<Long, Boolean> doInBackground() { + long downloadId = ContentUriUtils.isContentUri(filePath) + ? DownloadItem.INVALID_DOWNLOAD_ID + : addCompletedDownload(fileName, description, mimeType, filePath, + fileSizeBytes, originalUrl, referrer, downloadGuid); + boolean success = ContentUriUtils.isContentUri(filePath) + || downloadId != DownloadItem.INVALID_DOWNLOAD_ID; + boolean canResolve = success + && DownloadManagerService.canResolveDownload( + filePath, mimeType, downloadId); + return Pair.create(downloadId, canResolve); } @Override - protected void onPostExecute(Long downloadId) { - nativeOnAddCompletedDownloadDone(callbackId, downloadId); + protected void onPostExecute(Pair<Long, Boolean> result) { + nativeOnAddCompletedDownloadDone(callbackId, result.first, result.second); } }; try { @@ -283,7 +300,7 @@ } catch (RejectedExecutionException e) { // Reaching thread limit, update will be reschduled for the next run. Log.e(TAG, "Thread limit reached, reschedule notification update later."); - nativeOnAddCompletedDownloadDone(callbackId, DownloadItem.INVALID_DOWNLOAD_ID); + nativeOnAddCompletedDownloadDone(callbackId, DownloadItem.INVALID_DOWNLOAD_ID, false); } } @@ -424,5 +441,6 @@ } } - private static native void nativeOnAddCompletedDownloadDone(long callbackId, long downloadId); + private static native void nativeOnAddCompletedDownloadDone( + long callbackId, long downloadId, boolean canResolve); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index 72b0684d..d648b8a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -886,6 +886,23 @@ : ExternalNavigationDelegateImpl.resolveIntent(intent, true); } + /** + * Return whether a download item can be resolved to any activity. + * @param filePath The file path for the download. + * @param mimeType The mime type of the download + * @param systemDownloadId They download ID generated from the android DownloadManager. + * @return True, if the download can be handled by an activity, false otherwise + */ + public static boolean canResolveDownload( + String filePath, String mimeType, long systemDownloadId) { + assert !ThreadUtils.runningOnUiThread(); + if (isOMADownloadDescription(mimeType)) return true; + + Intent intent = getLaunchIntentForDownload(filePath, systemDownloadId, + DownloadManagerService.isSupportedMimeType(mimeType), null, null); + return intent != null && ExternalNavigationDelegateImpl.resolveIntent(intent, true); + } + /** See {@link #openDownloadedContent(Context, String, boolean, boolean, String, long)}. */ protected void openDownloadedContent(final DownloadInfo downloadInfo, final long downloadId, @DownloadOpenSource int source) { @@ -1196,18 +1213,25 @@ */ public void onSuccessNotificationShown( DownloadInfo info, boolean canResolve, int notificationId, long systemDownloadId) { - if (canResolve && shouldOpenAfterDownload(info.getMimeType(), info.hasUserGesture())) { - DownloadItem item = new DownloadItem(false, info); - item.setSystemDownloadId(systemDownloadId); - handleAutoOpenAfterDownload(item); - } else { - DownloadInfoBarController infobarController = - getInfoBarController(info.isOffTheRecord()); - if (infobarController != null) { - infobarController.onNotificationShown(info.getContentId(), notificationId); + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) { + if (canResolve && shouldOpenAfterDownload(info.getMimeType(), info.hasUserGesture())) { + DownloadItem item = new DownloadItem(false, info); + item.setSystemDownloadId(systemDownloadId); + handleAutoOpenAfterDownload(item); + } else { + DownloadInfoBarController infobarController = + getInfoBarController(info.isOffTheRecord()); + if (infobarController != null) { + infobarController.onNotificationShown(info.getContentId(), notificationId); + } + mDownloadSnackbarController.onDownloadSucceeded( + info, notificationId, systemDownloadId, canResolve, false); } - mDownloadSnackbarController.onDownloadSucceeded( - info, notificationId, systemDownloadId, canResolve, false); + } else { + if (getInfoBarController(info.isOffTheRecord()) != null) { + getInfoBarController(info.isOffTheRecord()) + .onNotificationShown(info.getContentId(), notificationId); + } } if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java index ef0ae9ffd..2b65a3e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
@@ -33,6 +33,7 @@ import org.chromium.base.ContentUriUtils; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.media.MediaViewerUtils; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; @@ -242,7 +243,9 @@ if (downloadUpdate.getIsOpenable()) { Intent intent; - if (LegacyHelpers.isLegacyDownload(downloadUpdate.getContentId())) { + if (LegacyHelpers.isLegacyDownload(downloadUpdate.getContentId()) + && !ChromeFeatureList.isEnabled( + ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) { Preconditions.checkNotNull(downloadUpdate.getContentId()); Preconditions.checkArgument(downloadUpdate.getSystemDownloadId() != -1 || ContentUriUtils.isContentUri(downloadUpdate.getFilePath()));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java index c70a6f77..cbad533 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java
@@ -88,6 +88,8 @@ mSupportFullWidthImages = !DeviceFormFactor.isNonMultiDisplayContextOnTablet( ContextUtils.getApplicationContext()); mUseGenericViewTypes = SysUtils.isLowEndDevice(); + mUseNewDownloadPath = ChromeFeatureList.isEnabled( + ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER); } public Builder setIsOffTheRecord(boolean isOffTheRecord) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java index a8a466d34..4666b99 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java
@@ -242,7 +242,7 @@ shownState = CircularProgressView.UiState.PAUSED; break; case OfflineItemState.INTERRUPTED: - shownState = item.isResumable ? CircularProgressView.UiState.PAUSED + shownState = item.isResumable ? CircularProgressView.UiState.RUNNING : CircularProgressView.UiState.RETRY; break; case OfflineItemState.COMPLETE: // Intentional fallthrough.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java index 81930c7b..d884cda 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java
@@ -7,6 +7,7 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.offline_items_collection.OfflineContentProvider; @@ -17,7 +18,7 @@ public class OfflineContentAggregatorFactory { // TODO(crbug.com/857543): Remove this after downloads have implemented it. // We need only one provider, since OfflineContentAggregator lives in the original profile. - private static DownloadBlockedOfflineContentProvider sBlockedProvider; + private static OfflineContentProvider sProvider; private OfflineContentAggregatorFactory() {} @@ -32,9 +33,9 @@ public static void setOfflineContentProviderForTests( @Nullable OfflineContentProvider provider) { if (provider == null) { - sBlockedProvider = null; + sProvider = null; } else { - sBlockedProvider = new DownloadBlockedOfflineContentProvider(provider); + sProvider = getProvider(provider); } } @@ -45,11 +46,18 @@ * @return An {@link OfflineContentProvider} instance. */ public static OfflineContentProvider forProfile(Profile profile) { - if (sBlockedProvider == null) { - sBlockedProvider = new DownloadBlockedOfflineContentProvider( - nativeGetOfflineContentAggregatorForProfile(profile)); + if (sProvider == null) { + sProvider = getProvider(nativeGetOfflineContentAggregatorForProfile(profile)); } - return sBlockedProvider; + return sProvider; + } + + private static OfflineContentProvider getProvider(OfflineContentProvider provider) { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) { + return provider; + } else { + return new DownloadBlockedOfflineContentProvider(provider); + } } private static native OfflineContentProvider nativeGetOfflineContentAggregatorForProfile(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java index 66277b6..05e30fc7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java
@@ -61,6 +61,70 @@ .ReadableObjectPropertyKey<ListModel<ExploreSitesCategory>> CATEGORY_LIST_KEY = new PropertyModel.ReadableObjectPropertyKey<>(); + /** + * Custom layout manager that fixes the scrollbar size based on number of items + * to provide a scrollbar utility that will not shift as a recylcer view scrolls + * between items of different heights. + */ + private class StableScrollLayoutManager extends LinearLayoutManager { + // Fixes the scrollbar size so it will not resize. + private int mScrollValue; + + StableScrollLayoutManager(Context context) { + super(context); + setSmoothScrollbarEnabled(false); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + final int count = getItemCount(); + if (count > 0) { + mScrollValue = getHeight() / count; + return mScrollValue; + } + return 0; + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + // Fix the scroll range. + return Math.max((getItemCount() - 1) * mScrollValue, 0); + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + final int count = getChildCount(); + // If this was called before the recycler view fully initialized itself, return 0. + if (count <= 0) return 0; + + // Snap to bottom if we scrolled to the bottom. + if (findLastCompletelyVisibleItemPosition() == getItemCount() - 1) { + return Math.max((getItemCount() - 1) * mScrollValue, 0); + } + + // Find the first visible view and check that views are properly initialized. + // This includes if a view was recycled or swapped out just now. + int firstPos = findFirstVisibleItemPosition(); + if (firstPos == RecyclerView.NO_POSITION) return 0; + View view = findViewByPosition(firstPos); + if (view == null) return 0; + + // Top of the view in pixels + final int top = getDecoratedTop(view); + int height = getDecoratedMeasuredHeight(view); + int heightOfScreen; + if (height <= 0) { + heightOfScreen = 0; + } else { + heightOfScreen = Math.abs(mScrollValue * top / height); + } + if (heightOfScreen == 0 && firstPos > 0) { + return mScrollValue * firstPos - 1; + } + return (mScrollValue * firstPos) + heightOfScreen; + } + } + @IntDef({CatalogLoadingState.LOADING, CatalogLoadingState.SUCCESS, CatalogLoadingState.ERROR}) @Retention(RetentionPolicy.SOURCE) public @interface CatalogLoadingState { @@ -109,7 +173,7 @@ .build(); Context context = mView.getContext(); - mLayoutManager = new LinearLayoutManager(context); + mLayoutManager = new StableScrollLayoutManager(context); int iconSizePx = context.getResources().getDimensionPixelSize(R.dimen.tile_view_icon_size); RoundedIconGenerator iconGenerator = new RoundedIconGenerator(iconSizePx, iconSizePx, iconSizePx / 2,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java index d3af51d5..2394eff6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
@@ -24,7 +24,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.touchless.TouchlessNewTabPage; +import org.chromium.chrome.browser.touchless.TouchlessDelegate; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.content_public.browser.LoadUrlParams; @@ -46,7 +46,7 @@ } if (FeatureUtilities.isNoTouchModeEnabled()) { - return new TouchlessNewTabPage(activity, new TabShim(tab)); + return TouchlessDelegate.createTouchlessNewTabPage(activity, new TabShim(tab)); } if (ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java index 8896d15..74a06c14 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -338,7 +338,7 @@ int numberOfSuggestionsExposed = getNumberOfSuggestionsExposed(); if (!canUpdateSuggestions(numberOfSuggestionsExposed)) { mIsDataStale = true; - Log.d(TAG, "updateSuggestions: Category %d is stale, it can't replace suggestions.", + Log.d(TAG, "updateModels: Category %d is stale, it can't replace suggestions.", getCategory()); return; } @@ -354,8 +354,7 @@ if (numberOfSuggestionsExposed > 0) { mIsDataStale = true; - Log.d(TAG, - "updateSuggestions: Category %d is stale, will keep already seen suggestions.", + Log.d(TAG, "updateModels: Category %d is stale, will keep already seen suggestions.", getCategory()); } appendSuggestions(suggestions, /* keepSectionSize = */ true, @@ -377,8 +376,7 @@ int numberOfSuggestionsExposed = getNumberOfSuggestionsExposed(); if (keepSectionSize) { - Log.d(TAG, "updateSuggestions: keeping the first %d suggestion", - numberOfSuggestionsExposed); + Log.d(TAG, "updateModels: keeping the first %d suggestion", numberOfSuggestionsExposed); int numSuggestionsToAppend = Math.max(0, suggestions.size() - numberOfSuggestionsExposed); int itemCount = mSuggestions.size(); @@ -432,7 +430,7 @@ if (!hasSuggestions()) return true; // If we don't have any, we always accept updates. if (CardsVariationParameters.ignoreUpdatesForExistingSuggestions()) { - Log.d(TAG, "updateSuggestions: replacing existing suggestion disabled"); + Log.d(TAG, "updateModels: replacing existing suggestion disabled"); NewTabPageUma.recordUIUpdateResult( NewTabPageUma.ContentSuggestionsUIUpdateResult.FAIL_DISABLED); return false; @@ -441,7 +439,7 @@ if (numberOfSuggestionsExposed >= getSuggestionsCount() || mHasAppended) { // In case that suggestions got removed, we assume they already were seen. This might // be over-simplifying things, but given the rare occurences it should be good enough. - Log.d(TAG, "updateSuggestions: replacing existing suggestion not possible, all seen"); + Log.d(TAG, "updateModels: replacing existing suggestion not possible, all seen"); NewTabPageUma.recordUIUpdateResult( NewTabPageUma.ContentSuggestionsUIUpdateResult.FAIL_ALL_SEEN); return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java index 4c10d75..81e4f70f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateConfigs.java
@@ -4,15 +4,22 @@ package org.chromium.chrome.browser.omaha; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import org.chromium.base.CommandLine; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState; import org.chromium.chrome.browser.omaha.inline.FakeAppUpdateManagerWrapper; import org.chromium.components.variations.VariationsAssociatedData; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Locale; + /** * Helper class for retrieving experiment configuration values and for manually testing update * functionality. Use the following switches to test locally: @@ -43,6 +50,35 @@ private static final String INLINE_UPDATE_INSTALL_FAILED_SWITCH_VALUE = "inline_update_install_failed"; + private static final String UPDATE_FLOW_PARAM_NAME = "flow"; + + /** Possible update flow configurations. */ + @IntDef({UpdateFlowConfiguration.NEVER_SHOW, UpdateFlowConfiguration.INTENT_ONLY, + UpdateFlowConfiguration.INLINE_ONLY, UpdateFlowConfiguration.BEST_EFFORT}) + @Retention(RetentionPolicy.SOURCE) + public @interface UpdateFlowConfiguration { + /** Turns off all update indicators. */ + int NEVER_SHOW = 1; + + /** + * Requires Omaha to say an update is available, and only ever Intents out to Play Store. + */ + int INTENT_ONLY = 2; + + /** + * Requires both Omaha and Play Store to say an update is available. Only ever uses the + * inline update flow. + */ + int INLINE_ONLY = 3; + + /** + * Checks both Omaha and Play Store. If Omaha says there is an update available, but Play + * Store says there is no update available, Intents out to Play Store. If both Omaha and + * Play Store says an update is available, uses the inline update flow. + */ + int BEST_EFFORT = 4; + } + /** * @return The minimum required storage to show the update prompt or {@code -1} if there is no * minimum. @@ -165,4 +201,39 @@ } return value; } + + /** + * When the inline update flow is enabled, returns the variation for the current session. With + * the inline update flow disabled it returns {@link UpdateFlowConfiguration#INTENT_ONLY}. + * @return the current inline update flow configuration. + */ + @UpdateFlowConfiguration + static int getConfiguration() { + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.INLINE_UPDATE_FLOW)) { + // Always use the the old flow if the inline update flow feature is not enabled. + return UpdateFlowConfiguration.INTENT_ONLY; + } + + switch (getFieldTrialConfigurationLowerCase()) { + case "never_show": + return UpdateFlowConfiguration.NEVER_SHOW; + case "intent_only": + return UpdateFlowConfiguration.INTENT_ONLY; + case "inline_only": + return UpdateFlowConfiguration.INLINE_ONLY; + case "best_effort": + return UpdateFlowConfiguration.BEST_EFFORT; + default: + // By just turning on the feature flag, assume INLINE_ONLY. + return UpdateFlowConfiguration.INLINE_ONLY; + } + } + + @NonNull + private static String getFieldTrialConfigurationLowerCase() { + String configuration = ChromeFeatureList.getFieldTrialParamByFeature( + ChromeFeatureList.INLINE_UPDATE_FLOW, UPDATE_FLOW_PARAM_NAME); + if (configuration == null) return ""; + return configuration.toLowerCase(Locale.US); + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateInfoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateInfoBarController.java index 1ad526a5..377cbdc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateInfoBarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateInfoBarController.java
@@ -10,6 +10,7 @@ import org.chromium.chrome.browser.infobar.InfoBarIdentifier; import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; import org.chromium.chrome.browser.lifecycle.Destroyable; +import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateInteractionSource; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateStatus; import org.chromium.chrome.browser.tab.Tab; @@ -60,12 +61,13 @@ } private void restartChrome() { - UpdateStatusProvider.getInstance().finishInlineUpdate(); + UpdateStatusProvider.getInstance().finishInlineUpdate(UpdateInteractionSource.FROM_INFOBAR); } private void retryUpdate() { if (mActivity == null) return; - UpdateStatusProvider.getInstance().startInlineUpdate(mActivity); + UpdateStatusProvider.getInstance().retryInlineUpdate( + UpdateInteractionSource.FROM_INFOBAR, mActivity); } private void showRestartInfobar() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java index 666bc49..ef289237 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java
@@ -25,6 +25,7 @@ import org.chromium.base.ObserverList; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; +import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateInteractionSource; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateStatus; import org.chromium.chrome.browser.preferences.PrefServiceBridge; @@ -208,13 +209,16 @@ } break; case UpdateState.INLINE_UPDATE_AVAILABLE: - UpdateStatusProvider.getInstance().startInlineUpdate(activity); + UpdateStatusProvider.getInstance().startInlineUpdate( + UpdateInteractionSource.FROM_MENU, activity); break; case UpdateState.INLINE_UPDATE_READY: - UpdateStatusProvider.getInstance().finishInlineUpdate(); + UpdateStatusProvider.getInstance().finishInlineUpdate( + UpdateInteractionSource.FROM_MENU); break; case UpdateState.INLINE_UPDATE_FAILED: - UpdateStatusProvider.getInstance().startInlineUpdate(activity); + UpdateStatusProvider.getInstance().retryInlineUpdate( + UpdateInteractionSource.FROM_MENU, activity); break; case UpdateState.UNSUPPORTED_OS_VERSION: // Intentional fall through.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java index 506f339..bd9d701 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateStatusProvider.java
@@ -28,6 +28,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.AsyncTask; import org.chromium.base.task.AsyncTask.Status; @@ -48,19 +49,37 @@ * For manually testing this functionality, see {@link UpdateConfigs}. */ public class UpdateStatusProvider implements ActivityStateListener { - /** Possible update states. */ + /** + * Possible sources of user interaction regarding updates. + * Treat this as append only as it is used by UMA. + */ + @IntDef({UpdateInteractionSource.FROM_MENU, UpdateInteractionSource.FROM_INFOBAR}) + @Retention(RetentionPolicy.SOURCE) + public @interface UpdateInteractionSource { + int FROM_MENU = 0; + int FROM_INFOBAR = 1; + + int COUNT = 2; + } + + /** + * Possible update states. + * Treat this as append only as it is used by UMA. + */ @IntDef({UpdateState.NONE, UpdateState.UPDATE_AVAILABLE, UpdateState.UNSUPPORTED_OS_VERSION, UpdateState.INLINE_UPDATE_AVAILABLE, UpdateState.INLINE_UPDATE_DOWNLOADING, UpdateState.INLINE_UPDATE_READY, UpdateState.INLINE_UPDATE_FAILED}) @Retention(RetentionPolicy.SOURCE) public @interface UpdateState { - int NONE = 1; - int UPDATE_AVAILABLE = 2; - int UNSUPPORTED_OS_VERSION = 3; - int INLINE_UPDATE_AVAILABLE = 4; - int INLINE_UPDATE_DOWNLOADING = 5; - int INLINE_UPDATE_READY = 6; - int INLINE_UPDATE_FAILED = 7; + int NONE = 0; + int UPDATE_AVAILABLE = 1; + int UNSUPPORTED_OS_VERSION = 2; + int INLINE_UPDATE_AVAILABLE = 3; + int INLINE_UPDATE_DOWNLOADING = 4; + int INLINE_UPDATE_READY = 5; + int INLINE_UPDATE_FAILED = 6; + + int COUNT = 7; } /** A set of properties that represent the current update state for Chrome. */ @@ -119,6 +138,9 @@ private final UpdateQuery mOmahaQuery; private @Nullable UpdateStatus mStatus; + /** Whether or not we've recorded the initial update status yet. */ + private boolean mRecordedInitialStatus; + /** @return Returns a singleton of {@link UpdateStatusProvider}. */ public static UpdateStatusProvider getInstance() { return LazyHolder.INSTANCE; @@ -181,16 +203,32 @@ /** * Starts the inline update process, if possible. + * @source The source of the action (the UI that caused it). * @param activity An {@link Activity} that will be used to interact with Play. */ - public void startInlineUpdate(Activity activity) { + public void startInlineUpdate(@UpdateInteractionSource int source, Activity activity) { if (mStatus == null || mStatus.updateState != UpdateState.INLINE_UPDATE_AVAILABLE) return; + RecordHistogram.recordEnumeratedHistogram( + "GoogleUpdate.Inline.UI.Start.Source", source, UpdateInteractionSource.COUNT); + mInlineController.startUpdate(activity); + } + + /** + * Retries the inline update process, if possible. + * @param activity An {@link Activity} that will be used to interact with Play. + */ + public void retryInlineUpdate(@UpdateInteractionSource int source, Activity activity) { + if (mStatus == null || mStatus.updateState != UpdateState.INLINE_UPDATE_AVAILABLE) return; + RecordHistogram.recordEnumeratedHistogram( + "GoogleUpdate.Inline.UI.Retry.Source", source, UpdateInteractionSource.COUNT); mInlineController.startUpdate(activity); } /** Finishes the inline update process, which may involve restarting the app. */ - public void finishInlineUpdate() { + public void finishInlineUpdate(@UpdateInteractionSource int source) { if (mStatus == null || mStatus.updateState != UpdateState.INLINE_UPDATE_READY) return; + RecordHistogram.recordEnumeratedHistogram( + "GoogleUpdate.Inline.UI.Install.Source", source, UpdateInteractionSource.COUNT); mInlineController.completeUpdate(); } @@ -243,15 +281,44 @@ } } else { @UpdateState + int omahaState = mOmahaQuery.getResult().updateState; + @UpdateState int inlineState = mInlineController.getStatus(); - if (inlineState != UpdateState.NONE) { - mStatus.updateState = inlineState; - } + mStatus.updateState = resolveOmahaAndInlineStatus( + UpdateConfigs.getConfiguration(), omahaState, inlineState); + } + + if (!mRecordedInitialStatus) { + RecordHistogram.recordEnumeratedHistogram( + "GoogleUpdate.StartUp.State", mStatus.updateState, UpdateState.COUNT); + mRecordedInitialStatus = true; } pingObservers(); } + @VisibleForTesting + static @UpdateState int resolveOmahaAndInlineStatus( + @UpdateConfigs.UpdateFlowConfiguration int configuration, @UpdateState int omahaState, + @UpdateState int inlineState) { + switch (configuration) { + case UpdateConfigs.UpdateFlowConfiguration.NEVER_SHOW: + return UpdateState.NONE; + case UpdateConfigs.UpdateFlowConfiguration.INLINE_ONLY: + if (omahaState != UpdateState.UPDATE_AVAILABLE) return omahaState; + if (inlineState == UpdateState.NONE) return UpdateState.NONE; + return inlineState; + case UpdateConfigs.UpdateFlowConfiguration.BEST_EFFORT: + if (omahaState != UpdateState.UPDATE_AVAILABLE) return omahaState; + if (inlineState == UpdateState.NONE) return omahaState; + return inlineState; + case UpdateConfigs.UpdateFlowConfiguration.INTENT_ONLY: // Intentional fall through. + default: + // Fall back to use Omaha only and use the old flow. + return omahaState; + } + } + private static final class LazyHolder { private static final UpdateStatusProvider INSTANCE = new UpdateStatusProvider(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java index 4dc37b1..597d515 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/inline/PlayInlineUpdateController.java
@@ -8,6 +8,7 @@ import android.content.IntentSender.SendIntentException; import android.os.Handler; import android.os.Looper; +import android.support.annotation.IntDef; import android.support.annotation.Nullable; import com.google.android.play.core.appupdate.AppUpdateInfo; @@ -15,12 +16,17 @@ import com.google.android.play.core.install.InstallState; import com.google.android.play.core.install.InstallStateUpdatedListener; import com.google.android.play.core.install.model.AppUpdateType; +import com.google.android.play.core.install.model.InstallErrorCode; import com.google.android.play.core.install.model.InstallStatus; import com.google.android.play.core.install.model.UpdateAvailability; import org.chromium.base.Log; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Helper class for gluing interactions with the Play store's AppUpdateManager with Chrome. This * involves hooking up to Play as a listener for install state changes, should only happen if we are @@ -28,6 +34,50 @@ */ public class PlayInlineUpdateController implements InlineUpdateController, InstallStateUpdatedListener { + /** + * Converts Play's InstallErrorCode enum to a stable monotomically incrementing Chrome enum. + * This is used for metric stability. + * Treat this as append only as it is used by UMA. + */ + @IntDef({InstallErrorCodeMetrics.NO_ERROR, InstallErrorCodeMetrics.NO_ERROR_PARTIALLY_ALLOWED, + InstallErrorCodeMetrics.ERROR_UNKNOWN, InstallErrorCodeMetrics.ERROR_API_NOT_AVAILABLE, + InstallErrorCodeMetrics.ERROR_INVALID_REQUEST, + InstallErrorCodeMetrics.ERROR_INSTALL_UNAVAILABLE, + InstallErrorCodeMetrics.ERROR_INSTALL_NOT_ALLOWED, + InstallErrorCodeMetrics.ERROR_DOWNLOAD_NOT_PRESENT, + InstallErrorCodeMetrics.ERROR_INTERNAL_ERROR, InstallErrorCodeMetrics.ERROR_UNTRACKED}) + @Retention(RetentionPolicy.SOURCE) + public @interface InstallErrorCodeMetrics { + int NO_ERROR = 0; + int NO_ERROR_PARTIALLY_ALLOWED = 1; + int ERROR_UNKNOWN = 2; + int ERROR_API_NOT_AVAILABLE = 3; + int ERROR_INVALID_REQUEST = 4; + int ERROR_INSTALL_UNAVAILABLE = 5; + int ERROR_INSTALL_NOT_ALLOWED = 6; + int ERROR_DOWNLOAD_NOT_PRESENT = 7; + int ERROR_INTERNAL_ERROR = 8; + int ERROR_UNTRACKED = 9; + + int COUNT = 10; + } + + /** + * A list of possible Play API call site failures. + * Treat this as append only as it is used by UMA. + */ + @IntDef({CallFailure.START_FAILED, CallFailure.START_EXCEPTION, CallFailure.COMPLETE_FAILED, + CallFailure.QUERY_FAILED}) + @Retention(RetentionPolicy.SOURCE) + private @interface CallFailure { + int START_FAILED = 0; + int START_EXCEPTION = 1; + int COMPLETE_FAILED = 2; + int QUERY_FAILED = 3; + + int COUNT = 4; + } + private static final String TAG = "PlayInline"; private static final int RESULT_IN_APP_UPDATE_FAILED = 1; private static final int REQUEST_CODE = 8123; @@ -80,9 +130,12 @@ boolean success = mAppUpdateManager.startUpdateFlowForResult( mAppUpdateInfo, AppUpdateType.FLEXIBLE, activity, REQUEST_CODE); Log.i(TAG, "startUpdateFlowForResult() returned " + success); + + if (!success) recordCallFailure(CallFailure.START_FAILED); } catch (SendIntentException exception) { mInstallStatus = InstallStatus.FAILED; Log.i(TAG, "startUpdateFlowForResult() threw an exception."); + recordCallFailure(CallFailure.START_EXCEPTION); } // TODO(dtrainor): Use success. } @@ -96,6 +149,7 @@ }) .addOnFailureListener(exception -> { Log.i(TAG, "completeUpdate() failed."); + recordCallFailure(CallFailure.COMPLETE_FAILED); mInstallStatus = InstallStatus.FAILED; pushStatus(); }); @@ -106,6 +160,14 @@ public void onStateUpdate(InstallState state) { Log.i(TAG, "onStateUpdate(" + state.installStatus() + ", " + state.installErrorCode() + ")"); + + if (state.installStatus() != mInstallStatus) { + RecordHistogram.recordEnumeratedHistogram("GoogleUpdate.Inline.StateChange.Error." + + installStatusToEnumSuffix(state.installStatus()), + installErrorCodeToMetrics(state.installErrorCode()), + InstallErrorCodeMetrics.COUNT); + } + mInstallStatus = state.installStatus(); pushStatus(); } @@ -126,6 +188,7 @@ mUpdateAvailability = UpdateAvailability.UNKNOWN; mInstallStatus = InstallStatus.UNKNOWN; Log.i(TAG, "pullCurrentState() failed."); + recordCallFailure(CallFailure.QUERY_FAILED); pushStatus(); }); } @@ -173,4 +236,60 @@ return newStatus; } + + private static String installStatusToEnumSuffix(@InstallStatus int status) { + switch (status) { + case InstallStatus.UNKNOWN: + return "Unknown"; + case InstallStatus.REQUIRES_UI_INTENT: + return "RequiresUiIntent"; + case InstallStatus.PENDING: + return "Pending"; + case InstallStatus.DOWNLOADING: + return "Downloading"; + case InstallStatus.DOWNLOADED: + return "Downloaded"; + case InstallStatus.INSTALLING: + return "Installing"; + case InstallStatus.INSTALLED: + return "Installed"; + case InstallStatus.FAILED: + return "Failed"; + case InstallStatus.CANCELED: + return "Canceled"; + default: + return "Untracked"; + } + } + + private static @InstallErrorCodeMetrics int installErrorCodeToMetrics( + @InstallErrorCode int error) { + switch (error) { + case InstallErrorCode.NO_ERROR: + return InstallErrorCodeMetrics.NO_ERROR; + case InstallErrorCode.NO_ERROR_PARTIALLY_ALLOWED: + return InstallErrorCodeMetrics.NO_ERROR_PARTIALLY_ALLOWED; + case InstallErrorCode.ERROR_UNKNOWN: + return InstallErrorCodeMetrics.ERROR_UNKNOWN; + case InstallErrorCode.ERROR_API_NOT_AVAILABLE: + return InstallErrorCodeMetrics.ERROR_API_NOT_AVAILABLE; + case InstallErrorCode.ERROR_INVALID_REQUEST: + return InstallErrorCodeMetrics.ERROR_INVALID_REQUEST; + case InstallErrorCode.ERROR_INSTALL_UNAVAILABLE: + return InstallErrorCodeMetrics.ERROR_INSTALL_UNAVAILABLE; + case InstallErrorCode.ERROR_INSTALL_NOT_ALLOWED: + return InstallErrorCodeMetrics.ERROR_INSTALL_NOT_ALLOWED; + case InstallErrorCode.ERROR_DOWNLOAD_NOT_PRESENT: + return InstallErrorCodeMetrics.ERROR_DOWNLOAD_NOT_PRESENT; + case InstallErrorCode.ERROR_INTERNAL_ERROR: + return InstallErrorCodeMetrics.ERROR_INTERNAL_ERROR; + default: + return InstallErrorCodeMetrics.ERROR_UNTRACKED; + } + } + + private static void recordCallFailure(@CallFailure int failure) { + RecordHistogram.recordEnumeratedHistogram( + "GoogleUpdate.Inline.CallFailure", failure, CallFailure.COUNT); + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinder.java index 997dd54..1405cb2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinder.java
@@ -53,7 +53,7 @@ } else if (SuggestionListProperties.EMBEDDER.equals(propertyKey)) { view.listView.setEmbedder(model.get(SuggestionListProperties.EMBEDDER)); } else if (SuggestionListProperties.SUGGESTION_MODELS.equals(propertyKey)) { - view.adapter.updateSuggestions(model.get(SuggestionListProperties.SUGGESTION_MODELS)); + view.adapter.updateModels(model.get(SuggestionListProperties.SUGGESTION_MODELS)); view.listView.setSelection(0); } else if (SuggestionListProperties.USE_DARK_BACKGROUND.equals(propertyKey)) { view.listView.refreshPopupBackground(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 26d4038e..81032a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.app.Activity; import android.content.Context; import android.os.Handler; import android.support.annotation.Nullable; @@ -485,9 +484,38 @@ && mMethodData.keySet().iterator().next().startsWith(UrlConstants.HTTPS_URL_PREFIX); } - private void buildUI(Activity activity) { + /** @return Whether the UI was built. */ + private boolean buildUI(ChromeActivity activity) { assert activity != null; + // Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be + // allowed to switch tabs, which can happen if the user receives an external Intent. + mObservedTabModelSelector = activity.getTabModelSelector(); + mObservedTabModel = activity.getCurrentTabModel(); + mObservedTabModelSelector.addObserver(mSelectorObserver); + mObservedTabModel.addObserver(mTabModelObserver); + + // Only the currently selected tab is allowed to show the payment UI. + if (TabModelUtils.getCurrentWebContents(mObservedTabModel) != mWebContents) { + mJourneyLogger.setNotShown(NotShownReason.OTHER); + disconnectFromClientWithDebugMessage( + "Background tab is not allowed to show PaymentRequest UI"); + if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); + return false; + } + + // Catch any time the user enters the overview mode and dismiss the payment UI. + if (activity instanceof ChromeTabbedActivity) { + mOverviewModeBehavior = ((ChromeTabbedActivity) activity).getOverviewModeBehavior(); + if (mOverviewModeBehavior.overviewVisible()) { + mJourneyLogger.setNotShown(NotShownReason.OTHER); + disconnectFromClientWithDebugMessage("In tab overview mode"); + if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); + return false; + } + mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver); + } + List<AutofillProfile> profiles = null; if (mRequestShipping || mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail) { profiles = PersonalDataManager.getInstance().getProfilesToSuggest( @@ -531,6 +559,8 @@ mAddressEditor.setEditorDialog(mUI.getEditorDialog()); mCardEditor.setEditorDialog(mUI.getCardEditorDialog()); if (mContactEditor != null) mContactEditor.setEditorDialog(mUI.getEditorDialog()); + + return true; } private void createShippingSection( @@ -622,43 +652,16 @@ return; } - // Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be - // allowed to switch tabs, which can happen if the user receives an external Intent. - mObservedTabModelSelector = chromeActivity.getTabModelSelector(); - mObservedTabModel = chromeActivity.getCurrentTabModel(); - mObservedTabModelSelector.addObserver(mSelectorObserver); - mObservedTabModel.addObserver(mTabModelObserver); - - // Only the currently selected tab is allowed to show the payment UI. - if (TabModelUtils.getCurrentWebContents(mObservedTabModel) != mWebContents) { - mJourneyLogger.setNotShown(NotShownReason.OTHER); - disconnectFromClientWithDebugMessage( - "Background tab is not allowed to show PaymentRequest UI"); - if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); - return; - } - - // Catch any time the user enters the overview mode and dismiss the payment UI. - if (chromeActivity instanceof ChromeTabbedActivity) { - mOverviewModeBehavior = - ((ChromeTabbedActivity) chromeActivity).getOverviewModeBehavior(); - if (mOverviewModeBehavior.overviewVisible()) { - mJourneyLogger.setNotShown(NotShownReason.OTHER); - disconnectFromClientWithDebugMessage("In tab overview mode"); - if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); - return; - } - mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver); - } - mIsUserGestureShow = isUserGesture; - buildUI(chromeActivity); - if (!mShouldSkipShowingPaymentRequestUi) mUI.show(); + if (!mShouldSkipShowingPaymentRequestUi) { + if (!buildUI(chromeActivity)) return; + mUI.show(); + } - triggerPaymentAppUiSkipIfApplicable(); + triggerPaymentAppUiSkipIfApplicable(chromeActivity); } - private void triggerPaymentAppUiSkipIfApplicable() { + private void triggerPaymentAppUiSkipIfApplicable(ChromeActivity chromeActivity) { // If we are skipping showing the Payment Request UI, we should call into the // PaymentApp immediately after we determine the instruments are ready and UI is shown. if (mShouldSkipShowingPaymentRequestUi && isFinishedQueryingPaymentApps() @@ -667,6 +670,7 @@ PaymentInstrument selectedInstrument = (PaymentInstrument) mPaymentMethodsSection.getSelectedItem(); + if (!buildUI(chromeActivity)) return; // Do not skip to payment app if it is not the only one, it's not pre-selected, or if // skip-UI requires a user gesture in show(), which was not present. @@ -1829,15 +1833,20 @@ respondHasEnrolledInstrumentQuery(mHasEnrolledInstrument); } + ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents); + if (chromeActivity == null) { + mJourneyLogger.setNotShown(NotShownReason.OTHER); + disconnectFromClientWithDebugMessage("Unable to find Chrome activity"); + if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); + return; + } + // The list of payment instruments is ready to display. mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.DataType.PAYMENT_METHODS, selection, new ArrayList<>(mPendingInstruments)); if (mPaymentMethodsSectionAdditionalTextResourceId != 0) { - Context context = ChromeActivity.fromWebContents(mWebContents); - if (context != null) { - mPaymentMethodsSection.setAdditionalText( - context.getString(mPaymentMethodsSectionAdditionalTextResourceId)); - } + mPaymentMethodsSection.setAdditionalText( + chromeActivity.getString(mPaymentMethodsSectionAdditionalTextResourceId)); } // Record the number suggested payment methods and whether at least one of them was @@ -1855,7 +1864,7 @@ SettingsAutofillAndPaymentsObserver.getInstance().registerObserver(this); - triggerPaymentAppUiSkipIfApplicable(); + triggerPaymentAppUiSkipIfApplicable(chromeActivity); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java index 3e18e05..1aa2e8c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
@@ -151,9 +151,9 @@ resetList(); - boolean hasEntries = mCategory.showSites(SiteSettingsCategory.Type.USB) - ? addChosenObjects(sites) - : addWebsites(sites); + int chooserDataType = mCategory.getChooserDataType(); + boolean hasEntries = + chooserDataType == -1 ? addWebsites(sites) : addChosenObjects(sites); if (!hasEntries && mEmptyView != null) mEmptyView.setText(R.string.no_saved_website_settings);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java index e24cf81..fa1c27d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java
@@ -169,6 +169,19 @@ } /** + * Get the chooser data type {@link ContentSettingsType} corresponding to the given + * {@link ContentSettingsType}. + */ + public static int chooserDataTypeFrom(@ContentSettingsType int type) { + switch (type) { + case ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_GUARD: + return ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA; + default: + return -1; // Conversion unavailable. + } + } + + /** * Convert Type into preference String */ public static String preferenceKey(@Type int type) { @@ -223,6 +236,14 @@ } /** + * Returns the {@link ContentSettingsType} representing the chooser data type for this category, + * or -1 if this category does not have a chooser data type. + */ + public @ContentSettingsType int getChooserDataType() { + return chooserDataTypeFrom(contentSettingsType(mCategory)); + } + + /** * Returns whether this category is the specified type. */ public boolean showSites(@Type int type) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java index 7d3d038..1ec681f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java
@@ -132,7 +132,8 @@ // Autoplay permission is per-origin. queue.add(new ExceptionInfoFetcher(ContentSettingsType.CONTENT_SETTINGS_TYPE_AUTOPLAY)); // USB device permission is per-origin and per-embedder. - queue.add(new UsbInfoFetcher()); + queue.add(new ChooserExceptionInfoFetcher( + ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_GUARD)); // Clipboard info is per-origin. queue.add(new PermissionInfoFetcher(PermissionInfo.Type.CLIPBOARD)); // Sensors permission is per-origin. @@ -211,7 +212,8 @@ queue.add(new ExceptionInfoFetcher(ContentSettingsType.CONTENT_SETTINGS_TYPE_AUTOPLAY)); } else if (category.showSites(SiteSettingsCategory.Type.USB)) { // USB device permission is per-origin. - queue.add(new UsbInfoFetcher()); + queue.add(new ChooserExceptionInfoFetcher( + ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_GUARD)); } else if (category.showSites(SiteSettingsCategory.Type.CLIPBOARD)) { // Clipboard permission is per-origin. queue.add(new PermissionInfoFetcher(PermissionInfo.Type.CLIPBOARD)); @@ -313,11 +315,19 @@ } } - private class UsbInfoFetcher extends Task { + private class ChooserExceptionInfoFetcher extends Task { + final @ContentSettingsType int mChooserDataType; + + public ChooserExceptionInfoFetcher(@ContentSettingsType int type) { + mChooserDataType = SiteSettingsCategory.chooserDataTypeFrom(type); + } + @Override public void run() { - for (ChosenObjectInfo info : WebsitePreferenceBridge.getChosenObjectInfo( - ContentSettingsType.CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA)) { + if (mChooserDataType == -1) return; + + for (ChosenObjectInfo info : + WebsitePreferenceBridge.getChosenObjectInfo(mChooserDataType)) { String origin = info.getOrigin(); if (origin == null) continue; findOrCreateSite(origin, info.getEmbedder()).addChosenObjectInfo(info);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/OWNERS new file mode 100644 index 0000000..e58f618d --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/OWNERS
@@ -0,0 +1,3 @@ +file://components/send_tab_to_self/OWNERS + +# COMPONENT: UI>Browser>Sharing
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS index b961ce7..9eefd34 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -6,6 +6,7 @@ 'Tab\.java': [ "-chrome", "+chrome/android/java/src/org/chromium/chrome/browser/tab", + "-components", "+components/embedder_support/android/java/src/org/chromium/components/embedder_support/view", "+components/navigation_interception/android/java/src/org/chromium/components/navigation_interception", "+ui/android/java/src/org/chromium/ui/base",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridContainerViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridContainerViewBinder.java index d586932..8eb9d48 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridContainerViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridContainerViewBinder.java
@@ -18,6 +18,9 @@ import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +/** + * ViewBinder for TabGridContainer. + */ class TabGridContainerViewBinder { /** * Bind the given model to the given view, updating the payload in propertyKey.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewHolder.java index 87f9d1e0..f6ba2e39 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewHolder.java
@@ -16,7 +16,7 @@ import org.chromium.chrome.R; /** - * {@link android.support.v7.widget.RecyclerView.ViewHolder} for tab grid. Owns the tab info card + * {@link RecyclerView.ViewHolder} for tab grid. Owns the tab info card * and the associated view hierarchy. */ class TabGridViewHolder extends RecyclerView.ViewHolder { @@ -24,9 +24,9 @@ public final TextView title; public final ImageView thumbnail; public final ImageView closeButton; - public int mTabId; + private int mTabId; - public TabGridViewHolder(View itemView) { + private TabGridViewHolder(View itemView) { super(itemView); this.thumbnail = itemView.findViewById(R.id.tab_thumbnail); this.title = itemView.findViewById(R.id.tab_title);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java index 2fe1a3e..2f5cf26e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java
@@ -39,5 +39,5 @@ THUMBNAIL_FETCHER, TITLE, IS_SELECTED}; public static final PropertyKey[] ALL_KEYS_TAB_STRIP = new PropertyKey[] { - TAB_ID, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, IS_SELECTED}; + TAB_ID, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, IS_SELECTED, TITLE}; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarCoordinator.java index bd77276..16231f95 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarCoordinator.java
@@ -16,9 +16,9 @@ import org.chromium.ui.modelutil.PropertyModel; /** - * A coordinator for BottomTabStrip component. Manages the communication with - * {@link TabListCoordinator} & @{link BottomTabGridCoordinator} as well as the - * life-cycle of shared component objects. + * A coordinator for TabStripBottomToolbar component. Manages the communication with + * {@link TabListCoordinator}, {@link BottomTabGridCoordinator}, and + * {@link TabStripToolbarCoordinator}, as well as the life-cycle of shared component objects. */ public class TabStripBottomToolbarCoordinator implements Destroyable, TabStripBottomToolbarMediator.ResetHandler { @@ -32,8 +32,8 @@ /** * Creates a new {@link TabStripBottomToolbarCoordinator} */ - public TabStripBottomToolbarCoordinator(Context context, ViewGroup parentView) { - mContext = context; + public TabStripBottomToolbarCoordinator(ViewGroup parentView) { + mContext = parentView.getContext(); mTabStripToolbarModel = new PropertyModel(TabStripToolbarViewProperties.ALL_KEYS); mTabStripToolbarCoordinator = @@ -59,7 +59,7 @@ /** * Handles a reset event originated from {@link TabStripBottomToolbarMediator} - * when the bottom sheet is collaped. + * when the bottom sheet is collapsed. * * @param tabModel current {@link TabModel} instance. */ @@ -70,7 +70,7 @@ /** * Handles a reset event originated from {@link TabStripBottomToolbarMediator} - * when the bottom sheet is expanded and the component. + * when the bottom sheet is expanded. * * @param tabModel current {@link TabModel} instance. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarMediator.java index 444890d..5925ad2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripBottomToolbarMediator.java
@@ -29,7 +29,7 @@ interface ResetHandler { /** * Handles a reset event originated from {@link TabStripBottomToolbarMediator} - * when the bottom sheet is collaped. + * when the bottom sheet is collapsed. * * @param tabModel current {@link TabModel} instance. */ @@ -37,7 +37,7 @@ /** * Handles a reset event originated from {@link TabStripBottomToolbarMediator} - * when the bottom sheet is expanded and the component. + * when the bottom sheet is expanded. * * @param tabModel current {@link TabModel} instance. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewBinder.java index b0104e5..8b14fa5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewBinder.java
@@ -17,7 +17,7 @@ import org.chromium.ui.modelutil.PropertyModel; /** - * {@link org.chromium.ui.modelutil.SimpleRecyclerViewMcp.ViewBinder} for tab grid. + * {@link org.chromium.ui.modelutil.SimpleRecyclerViewMcp.ViewBinder} for tab strip. * This class supports both full and partial updates to the {@link TabStripViewHolder}. */ class TabStripViewBinder {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewHolder.java index 89b14cfa..1dab4e1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabStripViewHolder.java
@@ -13,13 +13,13 @@ import org.chromium.chrome.R; /** - * {@link RecyclerView.ViewHolder} for tabstrip. + * {@link RecyclerView.ViewHolder} for tab strip. */ class TabStripViewHolder extends RecyclerView.ViewHolder { - public int mTabId; + private int mTabId; public final ImageButton button; - public TabStripViewHolder(View itemView) { + private TabStripViewHolder(View itemView) { super(itemView); this.button = itemView.findViewById(R.id.tab_strip_item_button); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index f1b21971..b7a64eb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -303,11 +303,6 @@ } }; - mIsBottomToolbarVisible = FeatureUtilities.isBottomToolbarEnabled() - && (!FeatureUtilities.isAdaptiveToolbarEnabled() - || mActivity.getResources().getConfiguration().orientation - != Configuration.ORIENTATION_LANDSCAPE); - mIncognitoStateProvider = new IncognitoStateProvider(mActivity); mTabCountProvider = new TabCountProvider(); mThemeColorProvider = themeColorProvider; @@ -315,7 +310,6 @@ mToolbarProvider = AsyncViewProvider.of(controlContainer, R.id.toolbar_stub, R.id.toolbar); mToolbar = new TopToolbarCoordinator(controlContainer, mToolbarProvider); - mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible); mToolbarProvider.whenLoaded((toolbar) -> onToolbarInflationComplete(menuHandler, appMenuPropertiesDelegate, invalidator)); @@ -786,7 +780,13 @@ mActivity.findViewById(R.id.bottom_controls_stub), mActivity.getActivityTabProvider(), homeButtonListener, searchAcceleratorListener, shareButtonListener); + + mIsBottomToolbarVisible = FeatureUtilities.isBottomToolbarEnabled() + && (!FeatureUtilities.isAdaptiveToolbarEnabled() + || mActivity.getResources().getConfiguration().orientation + != Configuration.ORIENTATION_LANDSCAPE); mBottomControlsCoordinator.setBottomControlsVisible(mIsBottomToolbarVisible); + mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible); Toast.setGlobalExtraYOffset( mActivity.getResources().getDimensionPixelSize(R.dimen.bottom_toolbar_height)); @@ -978,7 +978,7 @@ mTabModelSelector.getModel(isIncognito).closeAllTabs(); }; mAppMenuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH()); - mBottomControlsCoordinator.initializeWithNative( + mBottomControlsCoordinator.initializeWithNative(mActivity, mActivity.getCompositorViewHolder().getResourceManager(), mActivity.getCompositorViewHolder().getLayoutManager(), wrapBottomToolbarClickListenerForIPH(tabSwitcherClickHandler),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java index 284d42d..e93ec6b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
@@ -4,21 +4,25 @@ package org.chromium.chrome.browser.toolbar.bottom; +import android.support.annotation.Nullable; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewStub; import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper; import org.chromium.chrome.browser.compositor.layouts.LayoutManager; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.compositor.layouts.ToolbarSwipeLayout; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; +import org.chromium.chrome.browser.tasks.tab_list_ui.TabStripBottomToolbarCoordinator; import org.chromium.chrome.browser.toolbar.IncognitoStateProvider; import org.chromium.chrome.browser.toolbar.MenuButton; import org.chromium.chrome.browser.toolbar.TabCountProvider; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsViewBinder.ViewHolder; +import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; @@ -36,7 +40,8 @@ private final BottomControlsMediator mMediator; /** The coordinator for the split toolbar's bottom toolbar component. */ - private final BottomToolbarCoordinator mBottomToolbarCoordinator; + private @Nullable BottomToolbarCoordinator mBottomToolbarCoordinator; + private @Nullable TabStripBottomToolbarCoordinator mTabStripCoordinator; /** * Build the coordinator that manages the bottom controls. @@ -63,9 +68,14 @@ mMediator = new BottomControlsMediator(model, fullscreenManager, root.getResources().getDimensionPixelOffset(R.dimen.bottom_toolbar_height)); - mBottomToolbarCoordinator = new BottomToolbarCoordinator( - root.findViewById(R.id.bottom_toolbar_stub), tabProvider, homeButtonListener, - searchAcceleratorListener, shareButtonListener); + if (FeatureUtilities.isTabGroupsAndroidEnabled()) { + mTabStripCoordinator = new TabStripBottomToolbarCoordinator( + root.findViewById(R.id.bottom_container_slot)); + } else { + mBottomToolbarCoordinator = new BottomToolbarCoordinator( + root.findViewById(R.id.bottom_toolbar_stub), tabProvider, homeButtonListener, + searchAcceleratorListener, shareButtonListener); + } } /** @@ -73,6 +83,7 @@ * dependencies. * <p> * Calling this must occur after the native library have completely loaded. + * @param chromeActivity ChromeActivity instance to use. * @param resourceManager A {@link ResourceManager} for loading textures into the compositor. * @param layoutManager A {@link LayoutManager} to attach overlays to. * @param tabSwitcherListener An {@link OnClickListener} that is triggered when the @@ -88,56 +99,80 @@ * @param incognitoStateProvider Notifies components when incognito mode is entered or exited. * @param topToolbarRoot The root {@link ViewGroup} of the top toolbar. */ - public void initializeWithNative(ResourceManager resourceManager, LayoutManager layoutManager, - OnClickListener tabSwitcherListener, OnClickListener newTabClickListener, - OnClickListener closeTabsClickListener, AppMenuButtonHelper menuButtonHelper, - OverviewModeBehavior overviewModeBehavior, WindowAndroid windowAndroid, - TabCountProvider tabCountProvider, IncognitoStateProvider incognitoStateProvider, - ViewGroup topToolbarRoot) { + public void initializeWithNative(ChromeActivity chromeActivity, ResourceManager resourceManager, + LayoutManager layoutManager, OnClickListener tabSwitcherListener, + OnClickListener newTabClickListener, OnClickListener closeTabsClickListener, + AppMenuButtonHelper menuButtonHelper, OverviewModeBehavior overviewModeBehavior, + WindowAndroid windowAndroid, TabCountProvider tabCountProvider, + IncognitoStateProvider incognitoStateProvider, ViewGroup topToolbarRoot) { mMediator.setLayoutManager(layoutManager); mMediator.setResourceManager(resourceManager); mMediator.setToolbarSwipeHandler(layoutManager.getToolbarSwipeHandler()); mMediator.setWindowAndroid(windowAndroid); - mBottomToolbarCoordinator.initializeWithNative(tabSwitcherListener, newTabClickListener, - closeTabsClickListener, menuButtonHelper, overviewModeBehavior, tabCountProvider, - incognitoStateProvider, topToolbarRoot); + if (mBottomToolbarCoordinator != null) { + mBottomToolbarCoordinator.initializeWithNative(tabSwitcherListener, newTabClickListener, + closeTabsClickListener, menuButtonHelper, overviewModeBehavior, + tabCountProvider, incognitoStateProvider, topToolbarRoot); + } + + if (mTabStripCoordinator != null) { + mTabStripCoordinator.initializeWithNative(chromeActivity.getTabModelSelector(), + chromeActivity.getTabContentManager(), chromeActivity, + chromeActivity.getBottomSheetController()); + mMediator.setBottomControlsVisible(true); + } } /** * @param isVisible Whether the bottom control is visible. */ public void setBottomControlsVisible(boolean isVisible) { + // TabStripCoordinator manages its own visibility + if (mTabStripCoordinator != null) return; + mMediator.setBottomControlsVisible(isVisible); - mBottomToolbarCoordinator.setBottomToolbarVisible(isVisible); + if (mBottomToolbarCoordinator != null) { + mBottomToolbarCoordinator.setBottomToolbarVisible(isVisible); + } } /** * Show the update badge over the bottom toolbar's app menu. */ public void showAppMenuUpdateBadge() { - mBottomToolbarCoordinator.showAppMenuUpdateBadge(); + if (mBottomToolbarCoordinator != null) { + mBottomToolbarCoordinator.showAppMenuUpdateBadge(); + } } /** * Remove the update badge. */ public void removeAppMenuUpdateBadge() { - mBottomToolbarCoordinator.removeAppMenuUpdateBadge(); + if (mBottomToolbarCoordinator != null) { + mBottomToolbarCoordinator.removeAppMenuUpdateBadge(); + } } /** * @return Whether the update badge is showing. */ public boolean isShowingAppMenuUpdateBadge() { - return mBottomToolbarCoordinator.isShowingAppMenuUpdateBadge(); + if (mBottomToolbarCoordinator != null) { + return mBottomToolbarCoordinator.isShowingAppMenuUpdateBadge(); + } + return false; } /** * @return The wrapper for the browsing mode toolbar's app menu button. */ public MenuButton getMenuButtonWrapper() { - return mBottomToolbarCoordinator.getMenuButtonWrapper(); + if (mBottomToolbarCoordinator != null) { + return mBottomToolbarCoordinator.getMenuButtonWrapper(); + } + return null; } /** @@ -153,7 +188,8 @@ * Clean up any state when the bottom controls component is destroyed. */ public void destroy() { - mBottomToolbarCoordinator.destroy(); + if (mBottomToolbarCoordinator != null) mBottomToolbarCoordinator.destroy(); + if (mTabStripCoordinator != null) mTabStripCoordinator.destroy(); mMediator.destroy(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsViewBinder.java index be4df4d..37f1df9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsViewBinder.java
@@ -44,8 +44,10 @@ final boolean showCompositedView = model.get(BottomControlsProperties.COMPOSITED_VIEW_VISIBLE); view.sceneLayer.setIsVisible(showCompositedView); - model.get(BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT) - .setBottomToolbarSceneLayersVisibility(showCompositedView); + if (model.get(BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT) != null) { + model.get(BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT) + .setBottomToolbarSceneLayersVisibility(showCompositedView); + } model.get(BottomControlsProperties.LAYOUT_MANAGER).requestUpdate(); } else if (BottomControlsProperties.LAYOUT_MANAGER == propertyKey) { assert view.sceneLayer == null; @@ -57,6 +59,7 @@ .addSceneOverlayToBack(view.sceneLayer); } else if (BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT == propertyKey) { assert view.sceneLayer != null; + assert model.get(BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT) != null; model.get(BottomControlsProperties.TOOLBAR_SWIPE_LAYOUT) .setBottomToolbarSceneLayers(new ScrollingBottomViewSceneLayer(view.sceneLayer), new ScrollingBottomViewSceneLayer(view.sceneLayer),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java index 4861197..9c198ab7f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -304,6 +304,7 @@ @Override public boolean shouldRecognizeSwipe(MotionEvent e1, MotionEvent e2) { + if (FeatureUtilities.isTabGroupsAndroidEnabled()) return false; if (FeatureUtilities.isGridTabSwitcherEnabled(getContext())) return false; if (isOnTabStrip(e1)) return false; if (mToolbar != null && mToolbar.shouldIgnoreSwipeGesture()) return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java index 45c28145..3d12cad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -30,6 +30,7 @@ import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin; +import org.chromium.chrome.browser.touchless.TouchlessDelegate; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.variations.VariationsAssociatedData; import org.chromium.ui.base.DeviceFormFactor; @@ -535,7 +536,8 @@ private static void cacheTabGroupsAndroidEnabled() { ChromePreferenceManager.getInstance().writeBoolean( ChromePreferenceManager.TAB_GROUPS_ANDROID_ENABLED_KEY, - ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID)); + !DeviceClassManager.enableAccessibilityLayout() + && ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID)); } /** @@ -557,8 +559,7 @@ private static boolean isDeviceEligibleForTabGroups() { return !SysUtils.isLowEndDevice() && !DeviceFormFactor.isNonMultiDisplayContextOnTablet( - ContextUtils.getApplicationContext()) - && !DeviceClassManager.enableAccessibilityLayout(); + ContextUtils.getApplicationContext()); } /** @@ -574,7 +575,7 @@ * @return Whether no-touch-mode is enabled. */ public static boolean isNoTouchModeEnabled() { - return CommandLine.getInstance().hasSwitch(ChromeSwitches.NO_TOUCH_MODE); + return TouchlessDelegate.TOUCHLESS_MODE_ENABLED; } /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 68e8433..829cfd50 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -4044,7 +4044,7 @@ Site paused </message> <message name="IDS_USAGE_STATS_SITE_PAUSED_EXPLANATION" desc="Message when a website is suspended due to exceeding a user-defined limit"> - Your <ph name="FQDN">%1$s</ph> timer ran out. It'll start again tomorrow. + Your <ph name="FQDN">%1$s<ex>www.amazon.com</ex></ph> timer ran out. It'll start again tomorrow. </message> <!-- Bottom Tab Grid strings -->
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 95252780..5207b6a 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/android/config.gni") import("//chrome/android/feed/feed_java_sources.gni") import("//components/feed/features.gni") import("//components/offline_pages/buildflags/features.gni") @@ -37,7 +38,6 @@ "java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java", "java/src/org/chromium/chrome/browser/ChromeStrictMode.java", "java/src/org/chromium/chrome/browser/ChromeStringConstants.java", - "java/src/org/chromium/chrome/browser/ChromeSwitches.java", "java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java", "java/src/org/chromium/chrome/browser/ChromeTabbedActivity2.java", "java/src/org/chromium/chrome/browser/ChromeVersionInfo.java", @@ -1634,7 +1634,6 @@ "java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java", "java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java", "java/src/org/chromium/chrome/browser/toolbar/top/ViewShiftingActionBarDelegate.java", - "java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java", "java/src/org/chromium/chrome/browser/tracing/TracingController.java", "java/src/org/chromium/chrome/browser/tracing/TracingNotificationManager.java", "java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java", @@ -1842,6 +1841,16 @@ chrome_java_sources += [ "java/src/org/chromium/chrome/browser/component_updater/VrAssetsComponentInstaller.java" ] } +if (notouch_build) { + chrome_java_sources += [ + "touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java", + "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java", + "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java", + ] +} else { + chrome_java_sources += [ "touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java" ] +} + chrome_test_java_sources = [ "javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java", "javatests/src/org/chromium/chrome/browser/AudioTest.java", @@ -2358,6 +2367,10 @@ "javatests/src/org/chromium/chrome/test/util/ChromeSigninUtilsTest.java", ] +if (notouch_build) { + chrome_test_java_sources += [ "touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java" ] +} + chrome_junit_test_java_sources = [ "junit/src/org/chromium/chrome/browser/AppIndexingUtilTest.java", "junit/src/org/chromium/chrome/browser/BitmapCacheTest.java", @@ -2397,6 +2410,8 @@ "junit/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManagerImplTest.java", "junit/src/org/chromium/chrome/browser/compositor/EventOffsetHandlerTest.java", "junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java", + "junit/src/org/chromium/chrome/browser/compositor/layouts/CompositorAnimationHandlerTest.java", + "junit/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutUpdateHost.java", "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java", "junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java", "junit/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelperTest.java", @@ -2482,6 +2497,7 @@ "junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java", "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java", + "junit/src/org/chromium/chrome/browser/omaha/UpdateStatusProviderTest.java", "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java", "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java", "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java_templates/ChromeSwitches.java.tmpl similarity index 82% rename from chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java rename to chrome/android/java_templates/ChromeSwitches.java.tmpl index 26aa391..0fa50fbf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java +++ b/chrome/android/java_templates/ChromeSwitches.java.tmpl
@@ -8,14 +8,10 @@ * Contains all of the command line switches that are specific to the chrome/ * portion of Chromium on Android. */ -public abstract class ChromeSwitches { +public abstract class ChromeSwitches {{ // Switches used from Java. Please continue switch style used Chrome where // options-have-hyphens and are_not_split_with_underscores. - /** Mimic a low end device */ - public static final String ENABLE_ACCESSIBILITY_TAB_SWITCHER = - "enable-accessibility-tab-switcher"; - /** Whether fullscreen support is disabled (auto hiding controls, etc...). */ public static final String DISABLE_FULLSCREEN = "disable-fullscreen"; @@ -68,40 +64,19 @@ public static final String DISABLE_LOFI_SNACKBAR = "disable-lo-fi-snackbar"; /** - * Forces the update state to be set to the given state if the value is {@link - * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#NONE_SWITCH_VALUE}, {@link - * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#UPDATE_AVAILABLE_SWITCH_VALUE}, - * {@link - * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#UNSUPPORTED_OS_VERSION_SWITCH_VALUE}. + * Forces the update state to be set to the given state if the value is {{@link + * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#NONE_SWITCH_VALUE}}, {{@link + * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#UPDATE_AVAILABLE_SWITCH_VALUE}}, + * {{@link + * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#UNSUPPORTED_OS_VERSION_SWITCH_VALUE}}. */ public static final String FORCE_UPDATE_MENU_UPDATE_TYPE = "force-update-menu-type"; /** - * Forces the update menu badge to show. This requires the update type to be valid as well. - * - * @see #FORCE_UPDATE_MENU_UPDATE_TYPE - */ - public static final String FORCE_SHOW_UPDATE_MENU_BADGE = "force-show-update-menu-badge"; - - /** - * Sets the market URL for Chrome for use in testing. This requires setting {@link - * #FORCE_UPDATE_MENU_UPDATE_TYPE} to {@link - * org.chromium.chrome.browser.omaha.UpdateMenuItemHelper#UPDATE_AVAILABLE_SWITCH_VALUE}. - * @see #FORCE_UPDATE_MENU_UPDATE_TYPE - */ - public static final String MARKET_URL_FOR_TESTING = "market-url-for-testing"; - - /** * Disable multiwindow tab merging for testing. */ public static final String DISABLE_TAB_MERGING_FOR_TESTING = "disable-tab-merging"; - /** - * Turn on No Touch Mode, which will replace ChromeTabbedActivity with a single tab, non-touchy - * alternative. - */ - public static final String NO_TOUCH_MODE = "no-touch-mode"; - /////////////////////////////////////////////////////////////////////////////////////////////// // Native Switches /////////////////////////////////////////////////////////////////////////////////////////////// @@ -122,18 +97,6 @@ public static final String GOOGLE_BASE_URL = "google-base-url"; /** - * Disable domain reliability - * Native switch - switches::kDisableDomainReliability - */ - public static final String DISABLE_DOMAIN_RELIABILITY = "disable-domain-reliability"; - - /** - * Specifies Android phone page loading progress bar animation. - * Native switch - switches::kProgressBarAnimation - */ - public static final String PROGRESS_BAR_ANIMATION = "progress-bar-animation"; - - /** * Enables overscroll of the on screen keyboard. With this flag on, the OSK will only resize the * visual viewport. * Native switch - switches::kEnableOSKOverscroll @@ -229,6 +192,8 @@ public static final String DISABLE_GOOGLE_PLAY_SERVICES_FOR_TESTING = "disable-google-play-services-for-testing"; +{NATIVE_STRINGS} + // Prevent instantiation. - private ChromeSwitches() {} -} + private ChromeSwitches() {{}} +}}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index c700c62..e83df53a6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -183,6 +183,8 @@ private final String mQuickActionUri; private final int mQuickActionCategory; private final long mLoggedEventId; + private final String mSearchUrlFull; + private final String mSearchUrlPreload; boolean mDidStartResolution; boolean mDidFinishResolution; @@ -206,12 +208,16 @@ * @param loggedEventId The EventID logged by the server, which should be recorded * and sent back to the server along with user action results * in a subsequent request. + * @param searchUrlFull The URL for the full search to present in the overlay, or + * empty. + * @param searchUrlPreload The URL for the search to preload into the overlay, or + * empty. */ FakeTapSearch(String nodeId, boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory, - long loggedEventId) { + long loggedEventId, String searchUrlFull, String searchUrlPreload) { super(nodeId); mIsNetworkUnavailable = isNetworkUnavailable; @@ -229,6 +235,8 @@ mQuickActionUri = quickActionUri; mQuickActionCategory = quickActionCategory; mLoggedEventId = loggedEventId; + mSearchUrlFull = searchUrlFull; + mSearchUrlPreload = searchUrlPreload; } /** @@ -242,7 +250,7 @@ String searchTerm, String displayText) { this(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText, "alternate-term", "", false, -7, 0, "", "", "", "", QuickActionCategory.NONE, - 0L); + 0L, "", ""); } @Override @@ -315,7 +323,8 @@ handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode, mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, mStartAdjust, mEndAdjust, mContextLanguage, mThumbnailUrl, mCaption, - mQuickActionUri, mQuickActionCategory, mLoggedEventId); + mQuickActionUri, mQuickActionCategory, mLoggedEventId, + mSearchUrlFull, mSearchUrlPreload); mActiveFakeTapSearch = null; mDidFinishResolution = true; @@ -334,30 +343,38 @@ */ public class FakeSlowResolveSearch extends FakeTapSearch { /** - * @param nodeId - * @param isNetworkUnavailable - * @param responseCode - * @param searchTerm - * @param displayText - * @param alternateTerm - * @param mid - * @param doPreventPreload - * @param startAdjust - * @param endAdjust - * @param contextLanguage - * @param thumbnailUrl - * @param caption - * @param quickActionUri - * @param quickActionCategory + * @param nodeId The id of the node where the touch event will be simulated. + * @param isNetworkUnavailable Whether the network is unavailable. + * @param responseCode The HTTP response code of the resolution. + * @param searchTerm The resolved search term. + * @param displayText The display text. + * @param alternateTerm The alternate text. + * @param mid The MID to specify a KP, or an empty string. + * @param doPreventPreload Whether search preload should be prevented. + * @param startAdjust The start adjustment of the selection. + * @param endAdjust The end adjustment of the selection. + * @param contextLanguage The language of the context determined by the server. + * @param thumbnailUrl The URL of a thumbnail to display. + * @param caption The caption to display. + * @param quickActionUri The URI for the intent associated with the quick action. + * @param quickActionCategory The category for the quick action. + * @param loggedEventId The EventID logged by the server, which should be recorded + * and sent back to the server along with user action results + * in a subsequent request. + * @param searchUrlFull The URL for the full search to present in the overlay, or + * empty. + * @param searchUrlPreload The URL for the search to preload into the overlay, or + * empty. */ FakeSlowResolveSearch(String nodeId, boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory, - long loggedEventId) { + long loggedEventId, String searchUrlFull, String searchUrlPreload) { super(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, startAdjust, endAdjust, contextLanguage, - thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId); + thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId, + searchUrlFull, searchUrlPreload); } @Override @@ -583,11 +600,12 @@ String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, - int quickActionCategory, long loggedEventId) { + int quickActionCategory, long loggedEventId, String searchUrlFull, + String searchUrlPreload) { mBaseManager.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, - quickActionCategory, loggedEventId); + quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload); } @Override @@ -636,23 +654,24 @@ registerFakeTapSearch(new FakeTapSearch("term", false, 200, "Term", "Term")); registerFakeTapSearch( new FakeTapSearch("resolution", false, 200, "Resolution", "Resolution")); - registerFakeTapSearch(new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche", - "alternate-term", "", false, 0, 0, "de", "", "", "", QuickActionCategory.NONE, 0)); + registerFakeTapSearch( + new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche", "alternate-term", + "", false, 0, 0, "de", "", "", "", QuickActionCategory.NONE, 0, "", "")); registerFakeTapSearch( new FakeTapSearch("intelligence", false, 200, "Intelligence", "Intelligence")); // Register a fake tap search that will fake a logged event ID from the server. registerFakeTapSearch(new FakeTapSearch("intelligence-logged-event-id", false, 200, "Intelligence", "Intelligence", "alternate-term", "", false, 0, 0, "", "", "", "", - QuickActionCategory.NONE, LOGGED_EVENT_ID)); + QuickActionCategory.NONE, LOGGED_EVENT_ID, "", "")); // Register a resolving search of "States" that expands to "United States". registerFakeSlowResolveSearch(new FakeSlowResolveSearch("states", false, 200, "States", "States", "alternate-term", "", false, -7, 0, "", "", "", "", - QuickActionCategory.NONE, 0)); + QuickActionCategory.NONE, 0, "", "")); registerFakeSlowResolveSearch(new FakeSlowResolveSearch("search", false, 200, "Search", "Search", "alternate-term", "", false, 0, 0, "", "", "", "", - QuickActionCategory.NONE, 0)); + QuickActionCategory.NONE, 0, "", "")); } /**
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 e33a43d..a4552ab 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
@@ -472,12 +472,14 @@ private final String mQuickActionUri; private final int mQuickActionCategory; private final long mLoggedEventId; + private final String mSearchUrlFull; + private final String mSearchUrlPreload; public FakeResponseOnMainThread(boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int startAdjust, int endAdjudst, String contextLanguage, String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory, - long loggedEventId) { + long loggedEventId, String searchUrlFull, String searchUrlPreload) { mIsNetworkUnavailable = isNetworkUnavailable; mResponseCode = responseCode; mSearchTerm = searchTerm; @@ -493,6 +495,8 @@ mQuickActionUri = quickActionUri; mQuickActionCategory = quickActionCategory; mLoggedEventId = loggedEventId; + mSearchUrlFull = searchUrlFull; + mSearchUrlPreload = searchUrlPreload; } @Override @@ -500,7 +504,8 @@ mFakeServer.handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode, mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, mStartAdjust, mEndAdjust, mContextLanguage, mThumbnailUrl, mCaption, - mQuickActionUri, mQuickActionCategory, mLoggedEventId); + mQuickActionUri, mQuickActionCategory, mLoggedEventId, mSearchUrlFull, + mSearchUrlPreload); } } @@ -511,7 +516,7 @@ private void fakeResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload) { fakeResponse(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, - null, doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0); + null, doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0, "", ""); } /** @@ -521,12 +526,14 @@ private void fakeResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage, String thumbnailUrl, - String caption, String quickActionUri, int quickActionCategory, long loggedEventId) { + String caption, String quickActionUri, int quickActionCategory, long loggedEventId, + String searchUrlFull, String searchUrlPreload) { if (mFakeServer.getSearchTermRequested() != null) { - InstrumentationRegistry.getInstrumentation().runOnMainSync(new FakeResponseOnMainThread( - isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, - doPreventPreload, startAdjust, endAdjust, contextLanguage, thumbnailUrl, - caption, quickActionUri, quickActionCategory, loggedEventId)); + InstrumentationRegistry.getInstrumentation().runOnMainSync( + new FakeResponseOnMainThread(isNetworkUnavailable, responseCode, searchTerm, + displayText, alternateTerm, mid, doPreventPreload, startAdjust, + endAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, + quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload)); } } @@ -2387,7 +2394,7 @@ waitForPanelToPeek(); fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term", - null, false, -14, 0, "", "", "", "", QuickActionCategory.NONE, 0); + null, false, -14, 0, "", "", "", "", QuickActionCategory.NONE, 0, "", ""); waitForSelectionToBe("United States Intelligence"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java index 130a293c..5dae7e5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java
@@ -38,9 +38,10 @@ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { - mRequest = new ContextualSearchRequest("barack obama", "barack", "", true); + mRequest = + new ContextualSearchRequest("barack obama", "barack", "", true, null, null); mNormalPriorityOnlyRequest = - new ContextualSearchRequest("woody allen", "allen", "", false); + new ContextualSearchRequest("woody allen", "allen", "", false, null, null); } }); } @@ -75,4 +76,28 @@ Assert.assertFalse(mRequest.isUsingLowPriority()); Assert.assertFalse(mNormalPriorityOnlyRequest.isUsingLowPriority()); } + + @Test + @SmallTest + @Feature({"ContextualSearch"}) + public void testServerProvidedUrls() { + String serverUrlFull = "https://www.google.com/search?obama&ctxs=2"; + String serverUrlPreload = "https://www.google.com/s?obama&ctxs=2&pf=c&sns=1"; + InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + mRequest = new ContextualSearchRequest( + "", "", "", true, serverUrlFull, serverUrlPreload); + mNormalPriorityOnlyRequest = + new ContextualSearchRequest("", "", "", false, serverUrlFull, null); + } + }); + Assert.assertTrue(mRequest.isUsingLowPriority()); + Assert.assertEquals(serverUrlPreload, mRequest.getSearchUrl()); + mRequest.setNormalPriority(); + Assert.assertFalse(mRequest.isUsingLowPriority()); + Assert.assertFalse(mNormalPriorityOnlyRequest.isUsingLowPriority()); + Assert.assertEquals(serverUrlFull, mRequest.getSearchUrl()); + Assert.assertEquals(serverUrlFull, mNormalPriorityOnlyRequest.getSearchUrl()); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java index 4cc2adf..e44d0c6c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -99,7 +99,7 @@ public void startSearchTermResolutionRequest(String selection) { // Skip native calls and immediately "resolve" the search term. onSearchTermResolutionResponse(true, 200, selection, selection, "", "", false, 0, 10, - "", "", "", "", QuickActionCategory.NONE, 0); + "", "", "", "", QuickActionCategory.NONE, 0, "", ""); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java index 125cbdf..bc7e60b6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -145,6 +145,7 @@ features.put(ChromeFeatureList.DOWNLOAD_HOME_SHOW_STORAGE_INFO, false); features.put(ChromeFeatureList.DOWNLOAD_HOME_V2, false); features.put(ChromeFeatureList.OVERSCROLL_HISTORY_NAVIGATION, false); + features.put(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER, false); ChromeFeatureList.setTestFeatures(features); mStubbedProvider = new StubbedProvider();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadInfoBarControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadInfoBarControllerTest.java index 7618ab2b..1c7c920 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadInfoBarControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadInfoBarControllerTest.java
@@ -164,6 +164,7 @@ @Test @SmallTest @Feature({"Download"}) + @Features.DisableFeatures(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER) public void testAccelerated() { OfflineItem offlineItem = createOfflineItem(OfflineItemState.IN_PROGRESS); offlineItem.isAccelerated = true; @@ -174,6 +175,7 @@ @Test @SmallTest @Feature({"Download"}) + @Features.DisableFeatures(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER) public void testMultipleDownloadInProgress() { OfflineItem item1 = createOfflineItem(OfflineItemState.IN_PROGRESS); mTestController.onDownloadItemUpdated(createDownloadItem(item1)); @@ -187,6 +189,7 @@ @Test @SmallTest @Feature({"Download"}) + @Features.DisableFeatures(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER) public void testAcceleratedChangesToDownloadingAfterDelay() { OfflineItem item1 = createOfflineItem(OfflineItemState.IN_PROGRESS); item1.isAccelerated = true;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java index b612ce86..26eb375 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -45,6 +45,7 @@ */ @RunWith(ParameterizedRunner.class) @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) +@Features.DisableFeatures(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER) public class DownloadNotificationServiceTest { private static final ContentId ID1 = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java index 8d4ba0aa..1c678b0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
@@ -20,12 +20,18 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CallbackHelper; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.components.offline_items_collection.ContentId; +import org.chromium.components.offline_items_collection.OfflineContentProvider; +import org.chromium.components.offline_items_collection.OfflineItem; +import org.chromium.components.offline_items_collection.OfflineItemState; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -194,6 +200,22 @@ } } + private class TestDownloadBackendObserver implements OfflineContentProvider.Observer { + @Override + public void onItemsAdded(ArrayList<OfflineItem> items) {} + + @Override + public void onItemRemoved(ContentId id) {} + + @Override + public void onItemUpdated(OfflineItem item) { + if (item.state == OfflineItemState.COMPLETE) { + mLastDownloadFilePath = item.filePath; + mHttpDownloadFinished.notifyCalled(); + } + } + } + @Override public Statement apply(final Statement base, Description description) { return super.apply(new Statement() { @@ -222,6 +244,8 @@ new SystemDownloadNotifier(), new Handler(), UPDATE_DELAY_MILLIS)); DownloadController.setDownloadNotificationService( DownloadManagerService.getDownloadManagerService()); + OfflineContentAggregatorFactory.forProfile(null).addObserver( + new TestDownloadBackendObserver()); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java index 5ab4ff8..0666e59 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java
@@ -63,6 +63,16 @@ public void setUpTest() throws Exception { super.setUpTest(); MockitoAnnotations.initMocks(this); + + Map<String, Boolean> features = new HashMap<>(); + features.put(ChromeFeatureList.DOWNLOADS_LOCATION_CHANGE, true); + features.put(ChromeFeatureList.DOWNLOAD_HOME_SHOW_STORAGE_INFO, true); + features.put(ChromeFeatureList.DOWNLOAD_HOME_V2, true); + features.put(ChromeFeatureList.OFFLINE_PAGES_PREFETCHING, true); + features.put(ChromeFeatureList.OVERSCROLL_HISTORY_NAVIGATION, false); + features.put(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER, false); + ChromeFeatureList.setTestFeatures(features); + StubbedOfflineContentProvider stubbedOfflineContentProvider = new StubbedOfflineContentProvider(); OfflineContentAggregatorFactory.setOfflineContentProviderForTests( @@ -79,14 +89,6 @@ stubbedOfflineContentProvider.addItem(item3); TrackerFactory.setTrackerForTests(mTracker); - - Map<String, Boolean> features = new HashMap<>(); - features.put(ChromeFeatureList.DOWNLOADS_LOCATION_CHANGE, true); - features.put(ChromeFeatureList.DOWNLOAD_HOME_SHOW_STORAGE_INFO, true); - features.put(ChromeFeatureList.DOWNLOAD_HOME_V2, true); - features.put(ChromeFeatureList.OFFLINE_PAGES_PREFETCHING, true); - features.put(ChromeFeatureList.OVERSCROLL_HISTORY_NAVIGATION, false); - ChromeFeatureList.setTestFeatures(features); } private void setUpUi() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java index 75c0989..715669d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
@@ -24,6 +24,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.UrlConstants; @@ -34,17 +35,20 @@ import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule; import org.chromium.chrome.browser.vr.util.NativeUiUtils; +import org.chromium.chrome.browser.vr.util.RenderTestUtils; import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils; import org.chromium.chrome.browser.vr.util.VrInfoBarUtils; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.NewTabPageTestUtils; +import org.chromium.chrome.test.util.RenderTestRule; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.ClickUtils; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.DOMUtils; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -63,6 +67,10 @@ @Rule public ChromeTabbedActivityVrTestRule mTestRule = new ChromeTabbedActivityVrTestRule(); + @Rule + public RenderTestRule mRenderTestRule = + new RenderTestRule("components/test/data/vr_browser_ui/render_tests"); + private WebXrVrTestFramework mWebXrVrTestFramework; private WebVrTestFramework mWebVrTestFramework; private VrBrowserTestFramework mVrBrowserTestFramework; @@ -486,43 +494,83 @@ } /** - * Tests navigation from a fullscreened WebVR to a WebVR page. + * Tests that the navigation buttons work only when they should, and are greyed out when not + * usable. */ @Test @MediumTest - public void testNavigationButtons() throws IllegalArgumentException, InterruptedException { + @Feature({"Browser", "RenderTest"}) + public void testNavigationButtons() + throws IllegalArgumentException, InterruptedException, IOException { + // TODO(https://crbug.com/930840): Remove this when the weird gradient behavior is fixed. + mRenderTestRule.setPixelDiffThreshold(2); Assert.assertFalse( "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled()); Assert.assertFalse( "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled()); + NativeUiUtils.clickElementAndWaitForUiQuiescence( + UserFriendlyElementName.OVERFLOW_MENU, new PointF()); + RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, + "navigation_buttons_both_disabled", mRenderTestRule); + // Opening a new tab shouldn't enable the back button - mTestRule.loadUrlInNewTab(getUrl(Page.PAGE_2D), false, TabLaunchType.FROM_CHROME_UI); + mTestRule.loadUrlInNewTab("about:blank", false, TabLaunchType.FROM_CHROME_UI); + final int tabId = mTestRule.getActivity().getActivityTab().getId(); Assert.assertFalse( "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled()); Assert.assertFalse( "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled()); + // Actually click on the back button and ensure it doesn't go back to the first tab. + NativeUiUtils.clickElement(UserFriendlyElementName.BACK_BUTTON, new PointF()); + NativeUiUtils.clickElementAndWaitForUiQuiescence( + UserFriendlyElementName.OVERFLOW_MENU, new PointF()); + RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, + "navigation_buttons_both_disabled", mRenderTestRule); + Assert.assertEquals("Back button navigated to previous tab", tabId, + mTestRule.getActivity().getActivityTab().getId()); + // Navigating to a new page should enable the back button - mTestRule.loadUrl(getUrl(Page.PAGE_WEBVR)); + mTestRule.loadUrl("chrome://version/"); Assert.assertTrue( "Back button is disabled.", VrBrowserTransitionUtils.isBackButtonEnabled()); Assert.assertFalse( "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled()); - // Navigating back should disable the back button and enable the forward button - VrBrowserTransitionUtils.navigateBack(); + // Overflow menu should still be visible since navigation doesn't close it. + NativeUiUtils.waitForUiQuiescence(); + RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, + "navigation_buttons_back_enabled", mRenderTestRule); + + // Navigating back should disable the back button and enable the forward button. + // We need to click twice - once to close the overflow menu, and once to actually click. + NativeUiUtils.clickElement(UserFriendlyElementName.BACK_BUTTON, new PointF()); + NativeUiUtils.clickElement(UserFriendlyElementName.BACK_BUTTON, new PointF()); ChromeTabUtils.waitForTabPageLoaded( - mTestRule.getActivity().getActivityTab(), getUrl(Page.PAGE_2D)); + mTestRule.getActivity().getActivityTab(), "about:blank"); Assert.assertFalse( "Back button is enabled.", VrBrowserTransitionUtils.isBackButtonEnabled()); Assert.assertTrue( "Forward button is disabled.", VrBrowserTransitionUtils.isForwardButtonEnabled()); + // Once again, click on the back button and ensure it doesn't go back to the first tab. + NativeUiUtils.clickElement(UserFriendlyElementName.BACK_BUTTON, new PointF()); + NativeUiUtils.clickElementAndWaitForUiQuiescence( + UserFriendlyElementName.OVERFLOW_MENU, new PointF()); + RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, + "navigation_buttons_forward_enabled", mRenderTestRule); + Assert.assertEquals("Back button navigated to previous tab", tabId, + mTestRule.getActivity().getActivityTab().getId()); + // Navigating forward should disable the forward button and enable the back button - VrBrowserTransitionUtils.navigateForward(); + NativeUiUtils.clickElement(UserFriendlyElementName.FORWARD_BUTTON, new PointF()); ChromeTabUtils.waitForTabPageLoaded( - mTestRule.getActivity().getActivityTab(), getUrl(Page.PAGE_WEBVR)); + mTestRule.getActivity().getActivityTab(), "chrome://version/"); Assert.assertTrue( "Back button is disabled.", VrBrowserTransitionUtils.isBackButtonEnabled()); Assert.assertFalse( "Forward button is enabled.", VrBrowserTransitionUtils.isForwardButtonEnabled()); + NativeUiUtils.clickElementAndWaitForUiQuiescence( + UserFriendlyElementName.OVERFLOW_MENU, new PointF()); + RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, + "navigation_buttons_back_enabled", mRenderTestRule); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java index 43b7a48..2a7b57b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
@@ -352,9 +352,12 @@ Assert.assertTrue("Did not get a focused frame", rfh != null); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<String> result = new AtomicReference<String>(); - rfh.executeJavaScript(js, (String r) -> { - result.set(r); - latch.countDown(); + // The JS execution needs to be started on the UI thread to avoid hitting a DCHECK. + ThreadUtils.runOnUiThreadBlocking(() -> { + rfh.executeJavaScript(js, (String r) -> { + result.set(r); + latch.countDown(); + }); }); try { if (!latch.await(timeout, TimeUnit.MILLISECONDS) && failOnTimeout) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java index 165283a..a2e25d4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java
@@ -21,9 +21,7 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; -import org.chromium.chrome.browser.compositor.layouts.Layout; -import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost; -import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab; +import org.chromium.chrome.browser.compositor.layouts.MockLayoutUpdateHost; import org.chromium.chrome.browser.util.MathUtils; import java.util.ArrayList; @@ -38,47 +36,13 @@ sdk = Build.VERSION_CODES.N_MR1) public final class CompositorAnimatorTest { /** A mock implementation of {@link LayoutUpdateHost} that tracks update requests. */ - private static class MockLayoutUpdateHost implements LayoutUpdateHost { + private static class MockLayoutUpdateHostWithCallback extends MockLayoutUpdateHost { private final CallbackHelper mUpdateCallbackHelper = new CallbackHelper(); @Override public void requestUpdate() { mUpdateCallbackHelper.notifyCalled(); } - - @Override - public void startHiding(int nextTabId, boolean hintAtTabSelection) {} - - @Override - public void doneHiding() {} - - @Override - public void doneShowing() {} - - @Override - public boolean isActiveLayout(Layout layout) { - return true; - } - - @Override - public void initLayoutTabFromHost(final int tabId) {} - - @Override - public LayoutTab createLayoutTab(int id, boolean incognito, boolean showCloseButton, - boolean isTitleNeeded, float maxContentWidth, float maxContentHeight) { - return null; - } - - @Override - public void releaseTabLayout(int id) {} - - @Override - public void releaseResourcesForTab(int tabId) {} - - @Override - public CompositorAnimationHandler getAnimationHandler() { - return null; - } } /** An animation update listener that counts calls to its methods. */ @@ -116,7 +80,7 @@ } /** A mock {@link LayoutUpdateHost} to track update requests. */ - private MockLayoutUpdateHost mHost; + private MockLayoutUpdateHostWithCallback mHost; /** The handler that is responsible for managing all {@link CompositorAnimator}s. */ private CompositorAnimationHandler mHandler; @@ -130,7 +94,7 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - mHost = new MockLayoutUpdateHost(); + mHost = new MockLayoutUpdateHostWithCallback(); mHandler = new CompositorAnimationHandler(mHost);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/CompositorAnimationHandlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/CompositorAnimationHandlerTest.java new file mode 100644 index 0000000..d3251d7 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/CompositorAnimationHandlerTest.java
@@ -0,0 +1,72 @@ +// 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.compositor.layouts; + +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandler; +import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; + +/** + * Unit tests for {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation}. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class CompositorAnimationHandlerTest { + private static final long FAST_DURATION_MS = 100; + private static final long SLOW_DURATION_MS = 1000; + + private CompositorAnimator mFastAnimation; + private CompositorAnimator mSlowAnimation; + private CompositorAnimationHandler mAnimations; + private LayoutUpdateHost mUpdateHost; + + @Test + @SmallTest + public void testConcurrentAnimationsFinishSeparately() { + mUpdateHost = new MockLayoutUpdateHostWithAnimationHandler(mAnimations); + mAnimations = new CompositorAnimationHandler(mUpdateHost); + + CompositorAnimator mFastAnimation = + CompositorAnimator.ofFloat(mAnimations, 0.f, 1.f, FAST_DURATION_MS, null); + CompositorAnimator mSlowAnimation = + CompositorAnimator.ofFloat(mAnimations, 0.f, 1.f, SLOW_DURATION_MS, null); + + mFastAnimation.start(); + mSlowAnimation.start(); + + CompositorAnimationHandler.setTestingMode(true); + + // Advances time to check that the fast animation will finish first. + mAnimations.pushUpdateInTestingMode(1 + FAST_DURATION_MS); + Assert.assertFalse(mFastAnimation.isRunning()); + Assert.assertTrue(mSlowAnimation.isRunning()); + + // Advances time to check that all animations are finished. + mAnimations.pushUpdateInTestingMode(1 + SLOW_DURATION_MS); + Assert.assertFalse(mFastAnimation.isRunning()); + Assert.assertFalse(mSlowAnimation.isRunning()); + } + + /** A mock implementation of {@link LayoutUpdateHost} with animation handler. */ + private class MockLayoutUpdateHostWithAnimationHandler extends MockLayoutUpdateHost { + private CompositorAnimationHandler mAnimationHandler; + + MockLayoutUpdateHostWithAnimationHandler(CompositorAnimationHandler animationHandler) { + mAnimationHandler = animationHandler; + } + + @Override + public CompositorAnimationHandler getAnimationHandler() { + return mAnimationHandler; + } + } +} \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutUpdateHost.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutUpdateHost.java new file mode 100644 index 0000000..69a0645 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutUpdateHost.java
@@ -0,0 +1,48 @@ +// Copyright 2017 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.compositor.layouts; + +import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandler; +import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab; + +/** A mock implementation of {@link LayoutUpdateHost}. */ +public class MockLayoutUpdateHost implements LayoutUpdateHost { + @Override + public void requestUpdate() {} + + @Override + public void startHiding(int nextTabId, boolean hintAtTabSelection) {} + + @Override + public void doneHiding() {} + + @Override + public void doneShowing() {} + + @Override + public boolean isActiveLayout(Layout layout) { + return true; + } + + @Override + public void initLayoutTabFromHost(final int tabId) {} + + @Override + public LayoutTab createLayoutTab(int id, boolean incognito, boolean showCloseButton, + boolean isTitleNeeded, float maxContentWidth, float maxContentHeight) { + return null; + } + + @Override + public void releaseTabLayout(int id) {} + + @Override + public void releaseResourcesForTab(int tabId) {} + + @Override + public CompositorAnimationHandler getAnimationHandler() { + return null; + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java index 13576e7..a3bc770f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java
@@ -58,6 +58,7 @@ public void setUp() { mModel = new ListItemModel(); Map<String, Boolean> testFeatures = new HashMap<>(); + testFeatures.put(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER, true); ChromeFeatureList.setTestFeatures(testFeatures); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java index 6b9a8ed0..d53925c 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -603,7 +603,7 @@ /** * Tests that the More button appends new suggestions after dismissing all items. The tricky * condition is that if a section is empty, we issue a fetch instead of a fetch-more. This means - * we are using the 'updateSuggestions()' flow to append to the list the user is looking at. + * we are using the 'updateModels()' flow to append to the list the user is looking at. */ @Test @Feature({"Ntp"})
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omaha/UpdateStatusProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omaha/UpdateStatusProviderTest.java new file mode 100644 index 0000000..c2f3c7f --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/omaha/UpdateStatusProviderTest.java
@@ -0,0 +1,126 @@ +// Copyright 2019 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.omaha; + +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.INLINE_UPDATE_AVAILABLE; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.INLINE_UPDATE_DOWNLOADING; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.INLINE_UPDATE_FAILED; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.INLINE_UPDATE_READY; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.NONE; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.UNSUPPORTED_OS_VERSION; +import static org.chromium.chrome.browser.omaha.UpdateStatusProvider.UpdateState.UPDATE_AVAILABLE; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import org.chromium.base.test.util.Feature; + +/** + * Unit tests for UpdateStatusProvider. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class UpdateStatusProviderTest { + private static void verify(@UpdateStatusProvider.UpdateState int expected, + @UpdateConfigs.UpdateFlowConfiguration int configuration, + @UpdateStatusProvider.UpdateState int omahaState, + @UpdateStatusProvider.UpdateState int inlineState) { + @UpdateStatusProvider.UpdateState + int result = UpdateStatusProvider.resolveOmahaAndInlineStatus( + configuration, omahaState, inlineState); + Assert.assertEquals("{config=" + configuration + ", omaha=" + omahaState + + ", inline=" + inlineState + "}", + expected, result); + } + + @Test + @Feature("omaha") + public void testNeverShow() { + @UpdateConfigs.UpdateFlowConfiguration + int config = UpdateConfigs.UpdateFlowConfiguration.NEVER_SHOW; + verify(NONE, config, NONE, NONE); + verify(NONE, config, NONE, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, NONE, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, NONE, INLINE_UPDATE_READY); + verify(NONE, config, NONE, INLINE_UPDATE_FAILED); + verify(NONE, config, UNSUPPORTED_OS_VERSION, NONE); + verify(NONE, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_READY); + verify(NONE, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_FAILED); + verify(NONE, config, UPDATE_AVAILABLE, NONE); + verify(NONE, config, UPDATE_AVAILABLE, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, UPDATE_AVAILABLE, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, UPDATE_AVAILABLE, INLINE_UPDATE_READY); + verify(NONE, config, UPDATE_AVAILABLE, INLINE_UPDATE_FAILED); + } + + @Test + @Feature("omaha") + public void testInlineOnly() { + @UpdateConfigs.UpdateFlowConfiguration + int config = UpdateConfigs.UpdateFlowConfiguration.INLINE_ONLY; + verify(NONE, config, NONE, NONE); + verify(NONE, config, NONE, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, NONE, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, NONE, INLINE_UPDATE_READY); + verify(NONE, config, NONE, INLINE_UPDATE_FAILED); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, NONE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_AVAILABLE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_DOWNLOADING); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_READY); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_FAILED); + verify(NONE, config, UPDATE_AVAILABLE, NONE); + verify(INLINE_UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_AVAILABLE); + verify(INLINE_UPDATE_DOWNLOADING, config, UPDATE_AVAILABLE, INLINE_UPDATE_DOWNLOADING); + verify(INLINE_UPDATE_READY, config, UPDATE_AVAILABLE, INLINE_UPDATE_READY); + verify(INLINE_UPDATE_FAILED, config, UPDATE_AVAILABLE, INLINE_UPDATE_FAILED); + } + + @Test + @Feature("omaha") + public void testIntentOnly() { + @UpdateConfigs.UpdateFlowConfiguration + int config = UpdateConfigs.UpdateFlowConfiguration.INTENT_ONLY; + verify(NONE, config, NONE, NONE); + verify(NONE, config, NONE, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, NONE, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, NONE, INLINE_UPDATE_READY); + verify(NONE, config, NONE, INLINE_UPDATE_FAILED); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, NONE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_AVAILABLE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_DOWNLOADING); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_READY); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_FAILED); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, NONE); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_AVAILABLE); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_DOWNLOADING); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_READY); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_FAILED); + } + + @Test + @Feature("omaha") + public void testBestEffort() { + @UpdateConfigs.UpdateFlowConfiguration + int config = UpdateConfigs.UpdateFlowConfiguration.BEST_EFFORT; + verify(NONE, config, NONE, NONE); + verify(NONE, config, NONE, INLINE_UPDATE_AVAILABLE); + verify(NONE, config, NONE, INLINE_UPDATE_DOWNLOADING); + verify(NONE, config, NONE, INLINE_UPDATE_READY); + verify(NONE, config, NONE, INLINE_UPDATE_FAILED); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, NONE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_AVAILABLE); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_DOWNLOADING); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_READY); + verify(UNSUPPORTED_OS_VERSION, config, UNSUPPORTED_OS_VERSION, INLINE_UPDATE_FAILED); + verify(UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, NONE); + verify(INLINE_UPDATE_AVAILABLE, config, UPDATE_AVAILABLE, INLINE_UPDATE_AVAILABLE); + verify(INLINE_UPDATE_DOWNLOADING, config, UPDATE_AVAILABLE, INLINE_UPDATE_DOWNLOADING); + verify(INLINE_UPDATE_READY, config, UPDATE_AVAILABLE, INLINE_UPDATE_READY); + verify(INLINE_UPDATE_FAILED, config, UPDATE_AVAILABLE, INLINE_UPDATE_FAILED); + } +}
diff --git a/chrome/android/touchless/OWNERS b/chrome/android/touchless/OWNERS new file mode 100644 index 0000000..af2050f --- /dev/null +++ b/chrome/android/touchless/OWNERS
@@ -0,0 +1,5 @@ +mthiesse@chromium.org +yfriedman@chromium.org + +# COMPONENT: Mobile>Touchless +# OS: Android
diff --git a/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java b/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java new file mode 100644 index 0000000..6d7d43f --- /dev/null +++ b/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java
@@ -0,0 +1,25 @@ +// Copyright 2019 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.touchless; + +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.native_page.NativePage; +import org.chromium.chrome.browser.native_page.NativePageHost; + +/** + * The fallback version of TouchlessDelegate, when touchless mode isn't enabled. + */ +public class TouchlessDelegate { + public static final boolean TOUCHLESS_MODE_ENABLED = false; + + public static NativePage createTouchlessNewTabPage( + ChromeActivity activity, NativePageHost host) { + return null; + } + + public static boolean isTouchlessNewTabPage(NativePage nativePage) { + return false; + } +} \ No newline at end of file
diff --git a/chrome/android/touchless/java/DEPS b/chrome/android/touchless/java/DEPS new file mode 100644 index 0000000..838459a9 --- /dev/null +++ b/chrome/android/touchless/java/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+content/public/android/java/src/org/chromium/content_public", +]
diff --git a/chrome/android/java/res/layout/new_tab_page_touchless.xml b/chrome/android/touchless/java/res/layout/new_tab_page_touchless.xml similarity index 100% rename from chrome/android/java/res/layout/new_tab_page_touchless.xml rename to chrome/android/touchless/java/res/layout/new_tab_page_touchless.xml
diff --git a/chrome/android/features/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java similarity index 100% rename from chrome/android/features/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java rename to chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java new file mode 100644 index 0000000..f9c8b6bb --- /dev/null +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java
@@ -0,0 +1,25 @@ +// Copyright 2019 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.touchless; + +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.native_page.NativePage; +import org.chromium.chrome.browser.native_page.NativePageHost; + +/** + * Provides an entry point into touchless code from the rest of Chrome. + */ +public class TouchlessDelegate { + public static final boolean TOUCHLESS_MODE_ENABLED = true; + + public static NativePage createTouchlessNewTabPage( + ChromeActivity activity, NativePageHost host) { + return new TouchlessNewTabPage(activity, host); + } + + public static boolean isTouchlessNewTabPage(NativePage nativePage) { + return nativePage instanceof TouchlessNewTabPage; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java similarity index 96% rename from chrome/android/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java rename to chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java index 60573de..9fd815b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java
@@ -7,11 +7,11 @@ import android.view.View; import android.view.ViewGroup; -import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.native_page.BasicNativePage; import org.chromium.chrome.browser.native_page.NativePageHost; +import org.chromium.chrome.touchless.R; /** * Condensed new tab page for touchless devices.
diff --git a/chrome/android/features/touchless/DEPS b/chrome/android/touchless/javatests/DEPS similarity index 100% rename from chrome/android/features/touchless/DEPS rename to chrome/android/touchless/javatests/DEPS
diff --git a/chrome/android/features/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java similarity index 98% rename from chrome/android/features/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java rename to chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java index 82e92ef..7c56b94a 100644 --- a/chrome/android/features/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java +++ b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java
@@ -31,7 +31,7 @@ * Tests for NoTouchActivity. */ @RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, ChromeSwitches.NO_TOUCH_MODE}) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class NoTouchActivityTest { private static final String TEST_PATH = "/chrome/test/data/android/simple.html";
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni index cf22063a..52466dd 100644 --- a/chrome/android/trichrome.gni +++ b/chrome/android/trichrome.gni
@@ -112,5 +112,6 @@ [ "//base/android/proguard/disable_all_obfuscation.flags" ] } } + deps += [ "//chrome/android:trichrome_dummy_resources" ] } }
diff --git a/chrome/android/trichrome/res_dummy/values/strings.xml b/chrome/android/trichrome/res_dummy/values/strings.xml new file mode 100644 index 0000000..a0d71c24 --- /dev/null +++ b/chrome/android/trichrome/res_dummy/values/strings.xml
@@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 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. --> + +<!-- DO NOT ADD MORE RESOURCES HERE --> +<resources> + <string name="dummy"></string> +</resources> \ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index e5242fd8..94b6f22 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1209,9 +1209,6 @@ <message name="IDS_OFFLINE_LOGIN_HTML" desc="Text which suggests enter as an existing user when valid network isn't presented."> If you've already registered on this device, you can <ph name="LINK2_START">$1<ex>>a<</ex></ph>sign in as an existing user<ph name="LINK2_END">$2<ex>>/a<</ex></ph>. </message> - <message name="IDS_KIOSK_APPS_BUTTON" desc="Text shown on a button that brings up the kiosk apps menu on login screen"> - Apps - </message> <message name="IDS_LOGIN_USER_ADDING_BANNER" desc="Text shown on a banner in user adding screen."> Add an account to multiple sign-in. All signed-in accounts can be accessed without a password, so this feature should only be used with trusted accounts. </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 902d34f..ef530460 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5187,6 +5187,9 @@ <message name="IDS_REOPEN_TAB_PROMO" desc="Text shown on promotional UI appearing next to the app menu button"> Reopen a tab if you accidentally closed it </message> + <message name="IDS_REOPEN_TAB_PROMO_SCREENREADER" desc="Text announced encouraging users to reopen a tab with the given shortcut"> + <ph name="SHORTCUT">$1<ex>CTRL+SHIFT+T</ex></ph> can reopen accidentally closed tabs + </message> <!-- Browser Hung Plugin Detector --> <if expr="is_win">
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp index 9c602ca..9d15311f 100644 --- a/chrome/app/profiles_strings.grdp +++ b/chrome/app/profiles_strings.grdp
@@ -325,6 +325,39 @@ <message name="IDS_DEFAULT_AVATAR_LABEL_25" desc="The label for the sun and cloud avatar."> Sun and clouds </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_27" desc="The label for the cat avatar."> + Cat + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_28" desc="The label for the corgi avatar."> + Corgi + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_29" desc="The label for the dragon avatar."> + Dragon + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_30" desc="The label for the elephant avatar."> + Elephant + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_31" desc="The label for the fox avatar."> + Fox + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_32" desc="The label for the monkey avatar."> + Monkey + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_33" desc="The label for the panda avatar."> + Panda + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_34" desc="The label for the penguin avatar."> + Penguin + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_35" desc="The label for the butterfly avatar."> + Butterfly + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_36" desc="The label for the rabbit avatar."> + Rabbit + </message> + <message name="IDS_DEFAULT_AVATAR_LABEL_37" desc="The label for the unicorn avatar."> + Unicorn + </message> <message name="IDS_PROFILES_LOCAL_PROFILE_STATE" desc="This is displayed underneath the profile name for profiles that are not signed in to sync."> Not signed in
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_cat.png b/chrome/app/theme/default_100_percent/common/origami/avatar_cat.png new file mode 100644 index 0000000..8b8dc618 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_cat.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_corgi.png b/chrome/app/theme/default_100_percent/common/origami/avatar_corgi.png new file mode 100644 index 0000000..733d8a3 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_corgi.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_dragon.png b/chrome/app/theme/default_100_percent/common/origami/avatar_dragon.png new file mode 100644 index 0000000..826fd46 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_dragon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_elephant.png b/chrome/app/theme/default_100_percent/common/origami/avatar_elephant.png new file mode 100644 index 0000000..7a8b48bc --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_elephant.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_fox.png b/chrome/app/theme/default_100_percent/common/origami/avatar_fox.png new file mode 100644 index 0000000..7aba442 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_fox.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_monkey.png b/chrome/app/theme/default_100_percent/common/origami/avatar_monkey.png new file mode 100644 index 0000000..00386f4 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_monkey.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_panda.png b/chrome/app/theme/default_100_percent/common/origami/avatar_panda.png new file mode 100644 index 0000000..408f67f --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_panda.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_penguin.png b/chrome/app/theme/default_100_percent/common/origami/avatar_penguin.png new file mode 100644 index 0000000..13d699b --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_penguin.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_pinkbutterfly.png b/chrome/app/theme/default_100_percent/common/origami/avatar_pinkbutterfly.png new file mode 100644 index 0000000..1d847119 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_pinkbutterfly.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_rabbit.png b/chrome/app/theme/default_100_percent/common/origami/avatar_rabbit.png new file mode 100644 index 0000000..1f842a17 --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_rabbit.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/origami/avatar_unicorn.png b/chrome/app/theme/default_100_percent/common/origami/avatar_unicorn.png new file mode 100644 index 0000000..7df13dc --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/origami/avatar_unicorn.png Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 1119bf6a..1793f310 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -209,6 +209,19 @@ <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_24" file="common/profile_avatar_note.png" /> <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_25" file="common/profile_avatar_sun_cloud.png" /> <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_26" file="common/profile_avatar_placeholder.png" /> + <if expr="not is_android and not chromeos"> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_27" file="common/origami/avatar_cat.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_28" file="common/origami/avatar_corgi.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_29" file="common/origami/avatar_dragon.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_30" file="common/origami/avatar_elephant.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_31" file="common/origami/avatar_fox.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_32" file="common/origami/avatar_monkey.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_33" file="common/origami/avatar_panda.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_34" file="common/origami/avatar_penguin.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_35" file="common/origami/avatar_pinkbutterfly.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_36" file="common/origami/avatar_rabbit.png" /> + <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_37" file="common/origami/avatar_unicorn.png" /> + </if> <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE" file="common/profile_avatar_placeholder_large.png" /> <structure type="chrome_scaled_image" name="IDR_PROFILES_DICE_TURN_ON_SYNC" file="common/turn_on_sync_illustration.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 2cf51abe..880d2fdc 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -989,6 +989,8 @@ "page_load_metrics/observers/https_engagement_metrics/https_engagement_service.h", "page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc", "page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h", + "page_load_metrics/observers/largest_contentful_paint_handler.cc", + "page_load_metrics/observers/largest_contentful_paint_handler.h", "page_load_metrics/observers/live_tab_count_page_load_metrics_observer.cc", "page_load_metrics/observers/live_tab_count_page_load_metrics_observer.h", "page_load_metrics/observers/loading_predictor_page_load_metrics_observer.cc", @@ -1322,6 +1324,8 @@ "previews/previews_service.h", "previews/previews_service_factory.cc", "previews/previews_service_factory.h", + "previews/previews_top_host_provider_impl.cc", + "previews/previews_top_host_provider_impl.h", "previews/previews_ui_tab_helper.cc", "previews/previews_ui_tab_helper.h", "previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc", @@ -1559,6 +1563,8 @@ "signin/signin_util.h", "site_details.cc", "site_details.h", + "site_isolation_policy.cc", + "site_isolation_policy.h", "speech/chrome_speech_recognition_manager_delegate.cc", "speech/chrome_speech_recognition_manager_delegate.h", "speech/speech_recognizer.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 1ce55a3b..1c354ac 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -643,6 +643,16 @@ #endif // OS_ANDROID #if defined(OS_ANDROID) +const FeatureEntry::FeatureParam + kInterestFeedLargerImagesFeatureVariationConstant[] = { + {"feed_ui_enabled", "true"}, + {"feed_server_endpoint", + "https://www.google.com/httpservice/noretry/DiscoverClankService/" + "FeedQuery"}}; +const FeatureEntry::FeatureVariation kInterestFeedFeatureVariations[] = { + {"(larger images)", kInterestFeedLargerImagesFeatureVariationConstant, + base::size(kInterestFeedLargerImagesFeatureVariationConstant), nullptr}}; + const FeatureEntry::FeatureVariation kRemoteSuggestionsFeatureVariations[] = { {"via content suggestion server (backed by ChromeReader)", nullptr, 0, "3313421"}, @@ -1793,6 +1803,10 @@ flag_descriptions::kSSLCommittedInterstitialsDescription, kOsAll, FEATURE_VALUE_TYPE(features::kSSLCommittedInterstitials)}, #if defined(OS_ANDROID) + {"enable-site-isolation-for-password-sites", + flag_descriptions::kSiteIsolationForPasswordSitesName, + flag_descriptions::kSiteIsolationForPasswordSitesDescription, kOsAndroid, + FEATURE_VALUE_TYPE(features::kSiteIsolationForPasswordSites)}, {"enable-site-per-process", flag_descriptions::kStrictSiteIsolationName, flag_descriptions::kStrictSiteIsolationDescription, kOsAndroid, SINGLE_VALUE_TYPE(switches::kSitePerProcess)}, @@ -2226,7 +2240,9 @@ {"interest-feed-content-suggestions", flag_descriptions::kInterestFeedContentSuggestionsName, flag_descriptions::kInterestFeedContentSuggestionsDescription, kOsAndroid, - FEATURE_VALUE_TYPE(feed::kInterestFeedContentSuggestions)}, + FEATURE_WITH_PARAMS_VALUE_TYPE(feed::kInterestFeedContentSuggestions, + kInterestFeedFeatureVariations, + "InterestFeedContentSuggestions")}, {"enable-ntp-remote-suggestions", flag_descriptions::kEnableNtpRemoteSuggestionsName, flag_descriptions::kEnableNtpRemoteSuggestionsDescription, kOsAndroid, @@ -2530,6 +2546,13 @@ kOsAll, FEATURE_VALUE_TYPE( autofill::features::kAutofillUpstreamEditableExpirationDate)}, + {"enable-autofill-do-not-upload-save-unsupported-cards", + flag_descriptions::kEnableAutofillDoNotUploadSaveUnsupportedCardsName, + flag_descriptions:: + kEnableAutofillDoNotUploadSaveUnsupportedCardsDescription, + kOsAll, + FEATURE_VALUE_TYPE( + autofill::features::kAutofillDoNotUploadSaveUnsupportedCards)}, {"enable-autofill-import-non-focusable-credit-card-forms", flag_descriptions::kEnableAutofillImportNonFocusableCreditCardFormsName, flag_descriptions:: @@ -2777,9 +2800,15 @@ kOutOfProcessHeapProfilingKeepSmallAllocationsDescription, kOsAll, SINGLE_VALUE_TYPE(heap_profiling::kMemlogKeepSmallAllocations)}, - {"memlog-sampling", flag_descriptions::kOutOfProcessHeapProfilingSampling, - flag_descriptions::kOutOfProcessHeapProfilingSamplingDescription, kOsAll, - SINGLE_VALUE_TYPE(heap_profiling::kMemlogSampling)}, + {"memlog-in-process", + flag_descriptions::kOutOfProcessHeapProfilingInProcess, + flag_descriptions::kOutOfProcessHeapProfilingInProcessDescription, kOsAll, + SINGLE_VALUE_TYPE(heap_profiling::kMemlogInProcess)}, + + {"memlog-sampling-rate", + flag_descriptions::kOutOfProcessHeapProfilingSamplingRate, + flag_descriptions::kOutOfProcessHeapProfilingSamplingRateDescription, + kOsAll, SINGLE_VALUE_TYPE(heap_profiling::kMemlogSamplingRate)}, {"memlog-stack-mode", flag_descriptions::kOOPHPStackModeName, flag_descriptions::kOOPHPStackModeDescription, kOsAll, @@ -3023,6 +3052,12 @@ flag_descriptions::kShowManagedUiDescription, kOsWin | kOsMac | kOsLinux | kOsCrOS, FEATURE_VALUE_TYPE(features::kShowManagedUi)}, + + {"link-managed-notice-to-management-page", + flag_descriptions::kLinkManagedNoticeToChromeUIManagementURLName, + flag_descriptions::kLinkManagedNoticeToChromeUIManagementURLDescription, + kOsWin | kOsMac | kOsLinux, + FEATURE_VALUE_TYPE(features::kLinkManagedNoticeToChromeUIManagementURL)}, #endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) #if !defined(OS_ANDROID)
diff --git a/chrome/browser/accessibility/OWNERS b/chrome/browser/accessibility/OWNERS index 2c85844e..84f2c83 100644 --- a/chrome/browser/accessibility/OWNERS +++ b/chrome/browser/accessibility/OWNERS
@@ -1,4 +1,6 @@ file://ui/accessibility/OWNERS +katie@chromium.org + # TEAM: chromium-accessibility@chromium.org # COMPONENT: UI>Accessibility
diff --git a/chrome/browser/accessibility/accessibility_labels_service.cc b/chrome/browser/accessibility/accessibility_labels_service.cc index 5c75bc3..122e4ddc 100644 --- a/chrome/browser/accessibility/accessibility_labels_service.cc +++ b/chrome/browser/accessibility/accessibility_labels_service.cc
@@ -34,12 +34,13 @@ } // static -void AccessibilityLabelsService::InitOffTheRecordPrefs(Profile* profile) { - DCHECK(profile->IsOffTheRecord()); - profile->GetPrefs()->SetBoolean(prefs::kAccessibilityImageLabelsEnabled, - false); - profile->GetPrefs()->SetBoolean(prefs::kAccessibilityImageLabelsOptInAccepted, - false); +void AccessibilityLabelsService::InitOffTheRecordPrefs( + Profile* off_the_record_profile) { + DCHECK(off_the_record_profile->IsOffTheRecord()); + off_the_record_profile->GetPrefs()->SetBoolean( + prefs::kAccessibilityImageLabelsEnabled, false); + off_the_record_profile->GetPrefs()->SetBoolean( + prefs::kAccessibilityImageLabelsOptInAccepted, false); } void AccessibilityLabelsService::Init() { @@ -70,8 +71,7 @@ // Hidden behind a feature flag. if (base::FeatureList::IsEnabled( - features::kExperimentalAccessibilityLabels) && - accessibility_state_utils::IsScreenReaderEnabled()) { + features::kExperimentalAccessibilityLabels)) { bool enabled = profile_->GetPrefs()->GetBoolean( prefs::kAccessibilityImageLabelsEnabled); ax_mode.set_mode(ui::AXMode::kLabelImages, enabled);
diff --git a/chrome/browser/accessibility/accessibility_labels_service.h b/chrome/browser/accessibility/accessibility_labels_service.h index 949e948..8213c146 100644 --- a/chrome/browser/accessibility/accessibility_labels_service.h +++ b/chrome/browser/accessibility/accessibility_labels_service.h
@@ -27,7 +27,7 @@ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); // Off the record profiles will default to having the feature disabled. - static void InitOffTheRecordPrefs(Profile* profile); + static void InitOffTheRecordPrefs(Profile* off_the_record_profile); void Init();
diff --git a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc index 0812abe..1e53230d 100644 --- a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc +++ b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc
@@ -32,64 +32,81 @@ AttachCurrentThread(), java_assistant_payment_request_delegate_); } -void AssistantPaymentRequestDelegate::OnGetPaymentInformation( +void AssistantPaymentRequestDelegate::OnContactInfoChanged( JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jboolean jsucceed, - const JavaParamRef<jobject>& jcard, - const JavaParamRef<jobject>& jaddress, - const JavaParamRef<jstring>& jpayer_name, - const JavaParamRef<jstring>& jpayer_phone, - const JavaParamRef<jstring>& jpayer_email, - jboolean jis_terms_and_services_accepted) { - std::unique_ptr<PaymentInformation> payment_info = - std::make_unique<PaymentInformation>(); - payment_info->succeed = jsucceed; - payment_info->is_terms_and_conditions_accepted = - jis_terms_and_services_accepted; - if (payment_info->succeed) { - if (jcard != nullptr) { - payment_info->card = std::make_unique<autofill::CreditCard>(); - autofill::PersonalDataManagerAndroid::PopulateNativeCreditCardFromJava( - jcard, env, payment_info->card.get()); + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jstring>& jpayer_name, + const base::android::JavaParamRef<jstring>& jpayer_phone, + const base::android::JavaParamRef<jstring>& jpayer_email) { + std::string name; + std::string phone; + std::string email; - auto guid = payment_info->card->billing_address_id(); - if (!guid.empty()) { - autofill::AutofillProfile* profile = - autofill::PersonalDataManagerFactory::GetForProfile( - ProfileManager::GetLastUsedProfile()) - ->GetProfileByGUID(guid); - if (profile != nullptr) - payment_info->billing_address = - std::make_unique<autofill::AutofillProfile>(*profile); - } - } - if (jaddress != nullptr) { - payment_info->shipping_address = - std::make_unique<autofill::AutofillProfile>(); - autofill::PersonalDataManagerAndroid::PopulateNativeProfileFromJava( - jaddress, env, payment_info->shipping_address.get()); - } - if (jpayer_name != nullptr) { - base::android::ConvertJavaStringToUTF8(env, jpayer_name, - &payment_info->payer_name); - } - if (jpayer_phone != nullptr) { - base::android::ConvertJavaStringToUTF8(env, jpayer_phone, - &payment_info->payer_phone); - } - if (jpayer_email != nullptr) { - base::android::ConvertJavaStringToUTF8(env, jpayer_email, - &payment_info->payer_email); - } + if (jpayer_name) { + base::android::ConvertJavaStringToUTF8(env, jpayer_name, &name); } - ui_controller_->OnGetPaymentInformation(std::move(payment_info)); + + if (jpayer_phone) { + base::android::ConvertJavaStringToUTF8(env, jpayer_phone, &phone); + } + + if (jpayer_email) { + base::android::ConvertJavaStringToUTF8(env, jpayer_email, &email); + } + + ui_controller_->OnContactInfoChanged(name, phone, email); } -void AssistantPaymentRequestDelegate::OnCancelButtonClicked( +void AssistantPaymentRequestDelegate::OnShippingAddressChanged( JNIEnv* env, - const base::android::JavaParamRef<jobject>& jcaller) { - ui_controller_->OnCancelButtonClicked(); + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jaddress) { + if (!jaddress) { + ui_controller_->OnShippingAddressChanged(nullptr); + return; + } + + auto shipping_address = std::make_unique<autofill::AutofillProfile>(); + autofill::PersonalDataManagerAndroid::PopulateNativeProfileFromJava( + jaddress, env, shipping_address.get()); + ui_controller_->OnShippingAddressChanged(std::move(shipping_address)); +} + +void AssistantPaymentRequestDelegate::OnCreditCardChanged( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jcard) { + if (!jcard) { + ui_controller_->OnCreditCardChanged(nullptr); + return; + } + + auto card = std::make_unique<autofill::CreditCard>(); + autofill::PersonalDataManagerAndroid::PopulateNativeCreditCardFromJava( + jcard, env, card.get()); + + auto guid = card->billing_address_id(); + if (!guid.empty()) { + autofill::AutofillProfile* profile = + autofill::PersonalDataManagerFactory::GetForProfile( + ProfileManager::GetLastUsedProfile()) + ->GetProfileByGUID(guid); + if (profile != nullptr) { + auto billing_address = + std::make_unique<autofill::AutofillProfile>(*profile); + ui_controller_->OnBillingAddressChanged(std::move(billing_address)); + } + } + + ui_controller_->OnCreditCardChanged(std::move(card)); +} + +void AssistantPaymentRequestDelegate::OnTermsAndConditionsChanged( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + jint state) { + ui_controller_->OnTermsAndConditionsChanged( + static_cast<TermsAndConditionsState>(state)); } base::android::ScopedJavaGlobalRef<jobject>
diff --git a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h index 43c48bf9..87545be 100644 --- a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h +++ b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h
@@ -15,22 +15,26 @@ explicit AssistantPaymentRequestDelegate(UiControllerAndroid* ui_controller); ~AssistantPaymentRequestDelegate(); - void OnGetPaymentInformation( + void OnContactInfoChanged( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, - jboolean jsucceed, - const base::android::JavaParamRef<jobject>& jcard, - const base::android::JavaParamRef<jobject>& jaddress, const base::android::JavaParamRef<jstring>& jpayer_name, const base::android::JavaParamRef<jstring>& jpayer_phone, - const base::android::JavaParamRef<jstring>& jpayer_email, - jboolean jis_terms_and_services_accepted); + const base::android::JavaParamRef<jstring>& jpayer_email); - // TODO(crbug.com/806868): Remove this once PR is using the actions carousel - // to show its buttons. - void OnCancelButtonClicked( + void OnShippingAddressChanged( JNIEnv* env, - const base::android::JavaParamRef<jobject>& jcaller); + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jaddress); + + void OnCreditCardChanged(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jcard); + + void OnTermsAndConditionsChanged( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + jint state); base::android::ScopedJavaGlobalRef<jobject> GetJavaObject();
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc index 9ae616f..a9685ea 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -321,13 +321,6 @@ JNIEnv* env = AttachCurrentThread(); - // TODO(crbug.com/806868): Remove this case once payment request reuses the - // carousel. - if (ui_delegate_->GetPaymentRequestOptions()) { - Java_AutofillAssistantUiController_clearActions(env, java_object_); - return; - } - bool has_close_or_cancel = false; auto chips = Java_AutofillAssistantUiController_createChipList(env); const auto& actions = ui_delegate_->GetActions(); @@ -338,7 +331,7 @@ switch (action.type) { case HIGHLIGHTED_ACTION: Java_AutofillAssistantUiController_addHighlightedActionButton( - env, java_object_, chips, text, i); + env, java_object_, chips, text, i, action.disabled); break; case NORMAL_ACTION: @@ -524,16 +517,36 @@ GetModel()); } -void UiControllerAndroid::OnGetPaymentInformation( - std::unique_ptr<PaymentInformation> payment_info) { - ui_delegate_->SetPaymentInformation(std::move(payment_info)); +void UiControllerAndroid::OnShippingAddressChanged( + std::unique_ptr<autofill::AutofillProfile> address) { + ui_delegate_->SetShippingAddress(std::move(address)); +} + +void UiControllerAndroid::OnBillingAddressChanged( + std::unique_ptr<autofill::AutofillProfile> address) { + ui_delegate_->SetBillingAddress(std::move(address)); +} + +void UiControllerAndroid::OnContactInfoChanged(std::string name, + std::string phone, + std::string email) { + ui_delegate_->SetContactInfo(name, phone, email); +} + +void UiControllerAndroid::OnCreditCardChanged( + std::unique_ptr<autofill::CreditCard> card) { + ui_delegate_->SetCreditCard(std::move(card)); +} + +void UiControllerAndroid::OnTermsAndConditionsChanged( + TermsAndConditionsState state) { + ui_delegate_->SetTermsAndConditions(state); } void UiControllerAndroid::OnPaymentRequestChanged( const PaymentRequestOptions* payment_options) { JNIEnv* env = AttachCurrentThread(); auto jmodel = GetPaymentRequestModel(); - UpdateActions(); if (!payment_options) { Java_AssistantPaymentRequestModel_clearOptions(env, jmodel); return;
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h index 51914b5b..5b60599 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.h +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -75,9 +75,15 @@ void OnFeedbackButtonClicked(); // Called by AssistantPaymentRequestDelegate: - void OnGetPaymentInformation( - std::unique_ptr<PaymentInformation> payment_info); - void OnCancelButtonClicked(); + void OnShippingAddressChanged( + std::unique_ptr<autofill::AutofillProfile> address); + void OnBillingAddressChanged( + std::unique_ptr<autofill::AutofillProfile> address); + void OnContactInfoChanged(std::string name, + std::string phone, + std::string email); + void OnCreditCardChanged(std::unique_ptr<autofill::CreditCard> card); + void OnTermsAndConditionsChanged(TermsAndConditionsState state); // Called by Java. void SnackbarResult(JNIEnv* env, @@ -140,6 +146,7 @@ // action after a short delay unless the user taps the undo button. void ShowSnackbar(const std::string& message, base::OnceCallback<void()> action); + void OnCancelButtonClicked(); void OnCancelButtonWithActionIndexClicked(int action_index); void OnCancel(int action_index);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc index 05848399..4104345 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -10,6 +10,7 @@ #include "base/base64.h" #include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/json/json_string_value_serializer.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -58,6 +59,8 @@ const char kContextualSearchThumbnail[] = "thumbnail"; const char kContextualSearchAction[] = "action"; const char kContextualSearchCategory[] = "category"; +const char kContextualSearchSearchUrlFull[] = "search_url_full"; +const char kContextualSearchSearchUrlPreload[] = "search_url_preload"; const char kActionCategoryAddress[] = "ADDRESS"; const char kActionCategoryEmail[] = "EMAIL"; @@ -74,6 +77,7 @@ // The version of the Contextual Cards API that we want to invoke. const int kContextualCardsUrlActions = 3; +const int kContextualCardsDefinitions = 4; const int kResponseCodeUninitialized = -1; @@ -215,12 +219,14 @@ std::string quick_action_uri = ""; int64_t logged_event_id = 0; QuickActionCategory quick_action_category = QUICK_ACTION_CATEGORY_NONE; + std::string search_url_full = ""; + std::string search_url_preload = ""; DecodeSearchTermFromJsonResponse( json_string, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id); + &logged_event_id, &search_url_full, &search_url_preload); if (mention_start != 0 || mention_end != 0) { // Sanity check that our selection is non-zero and it is less than // 100 characters as that would make contextual search bar hide. @@ -242,7 +248,8 @@ is_invalid, response_code, search_term, display_text, alternate_term, mid, prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust, context_language, thumbnail_url, caption, quick_action_uri, - quick_action_category, logged_event_id)); + quick_action_category, logged_event_id, search_url_full, + search_url_preload)); } std::string ContextualSearchDelegate::BuildRequestUrl( @@ -258,7 +265,13 @@ TemplateURLRef::SearchTermsArgs search_terms_args = TemplateURLRef::SearchTermsArgs(base::string16()); + // Set the Coca-integration version based on our current active feature, + // or an override param from our field trial. int contextual_cards_version = kContextualCardsUrlActions; + if (base::FeatureList::IsEnabled( + chrome::android::kContextualSearchDefinitions)) { + contextual_cards_version = kContextualCardsDefinitions; + } if (field_trial_->GetContextualCardsVersion() != 0) { contextual_cards_version = field_trial_->GetContextualCardsVersion(); } @@ -432,7 +445,9 @@ std::string* caption, std::string* quick_action_uri, QuickActionCategory* quick_action_category, - int64_t* logged_event_id) { + int64_t* logged_event_id, + std::string* search_url_full, + std::string* search_url_preload) { bool contains_xssi_escape = base::StartsWith(response, kXssiEscape, base::CompareCase::SENSITIVE); const std::string& proper_json = @@ -504,6 +519,11 @@ } } + // Contextual Cards V4 may also provide full search URLs to use in the + // overlay. + dict->GetString(kContextualSearchSearchUrlFull, search_url_full); + dict->GetString(kContextualSearchSearchUrlPreload, search_url_preload); + // Any Contextual Cards integration. // For testing purposes check if there was a diagnostic from Contextual // Cards and output that into the log.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h index 47903fb0..13d64af 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -150,7 +150,9 @@ std::string* caption, std::string* quick_action_uri, QuickActionCategory* quick_action_category, - int64_t* logged_event_id); + int64_t* logged_event_id, + std::string* search_url_full, + std::string* search_url_preload); // Extracts the start and end location from a mentions list, and sets the // integers referenced by |startResult| and |endResult|.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 71f975d8..04acfee 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -529,7 +529,12 @@ "\"info_text\":\"44th U.S. President\"," "\"display_text\":\"Barack Obama\", \"mentions\":[0,15]," "\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"," - "\"logged_event_id\":\"1234567890123456789\"}"; + "\"logged_event_id\":\"1234567890123456789\"," + "\"search_url_full\":\"https://www.google.com/" + "search?q=define+obscure&ctxs=2\"," + "\"search_url_preload\":\"https://www.google.com/" + "search?q=define+obscure&ctxs=2&pf=c&sns=1\"" + "}"; std::string search_term; std::string display_text; std::string alternate_term; @@ -543,12 +548,14 @@ std::string quick_action_uri; int64_t logged_event_id; QuickActionCategory quick_action_category = QUICK_ACTION_CATEGORY_NONE; + std::string search_url_full; + std::string search_url_preload; delegate_->DecodeSearchTermFromJsonResponse( json_with_escape, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id); + &logged_event_id, &search_url_full, &search_url_preload); EXPECT_EQ("obama", search_term); EXPECT_EQ("Barack Obama", display_text); @@ -561,6 +568,10 @@ EXPECT_EQ("", quick_action_uri); EXPECT_EQ(QUICK_ACTION_CATEGORY_NONE, quick_action_category); EXPECT_EQ(1234567890123456789, logged_event_id); + EXPECT_EQ("https://www.google.com/search?q=define+obscure&ctxs=2", + search_url_full); + EXPECT_EQ("https://www.google.com/search?q=define+obscure&ctxs=2&pf=c&sns=1", + search_url_preload); } TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) {
diff --git a/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc b/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc index be5a340..4b41395 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc
@@ -5,7 +5,9 @@ #include "chrome/browser/android/contextualsearch/contextual_search_field_trial.h" #include "base/command_line.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/string_number_conversions.h" +#include "chrome/browser/android/chrome_feature_list.h" #include "components/variations/variations_associated_data.h" namespace { @@ -117,6 +119,12 @@ std::string param_string = GetSwitch(name); if (param_string.empty()) param_string = GetParam(name); + // If we still didn't get a param, try getting a Feature param. + if (param_string.empty()) { + // For now, we just support the Contextual Search Definitions feature. + param_string = base::GetFieldTrialParamValueByFeature( + chrome::android::kContextualSearchDefinitions, name); + } int param_int; if (!param_string.empty() && base::StringToInt(param_string, ¶m_int))
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index afac380..409fd0c 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -180,6 +180,12 @@ base::android::ScopedJavaLocalRef<jstring> j_quick_action_uri = base::android::ConvertUTF8ToJavaString( env, resolved_search_term.quick_action_uri); + base::android::ScopedJavaLocalRef<jstring> j_search_url_full = + base::android::ConvertUTF8ToJavaString( + env, resolved_search_term.search_url_full); + base::android::ScopedJavaLocalRef<jstring> j_search_url_preload = + base::android::ConvertUTF8ToJavaString( + env, resolved_search_term.search_url_preload); Java_ContextualSearchManager_onSearchTermResolutionResponse( env, java_manager_, resolved_search_term.is_invalid, resolved_search_term.response_code, j_search_term, j_display_text, @@ -188,7 +194,8 @@ resolved_search_term.selection_end_adjust, j_context_language, j_thumbnail_url, j_caption, j_quick_action_uri, resolved_search_term.quick_action_category, - resolved_search_term.logged_event_id); + resolved_search_term.logged_event_id, j_search_url_full, + j_search_url_preload); } void ContextualSearchManager::OnTextSurroundingSelectionAvailable(
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.cc b/chrome/browser/android/contextualsearch/resolved_search_term.cc index df5ea61..cb30ae5 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.cc +++ b/chrome/browser/android/contextualsearch/resolved_search_term.cc
@@ -21,7 +21,9 @@ caption(""), quick_action_uri(""), quick_action_category(QUICK_ACTION_CATEGORY_NONE), - logged_event_id(0) {} + logged_event_id(0), + search_url_full(""), + search_url_preload("") {} ResolvedSearchTerm::ResolvedSearchTerm( bool is_invalid, @@ -38,7 +40,9 @@ const std::string& caption, const std::string& quick_action_uri, const QuickActionCategory& quick_action_category, - int64_t logged_event_id) + int64_t logged_event_id, + const std::string& search_url_full, + const std::string& search_url_preload) : is_invalid(is_invalid), response_code(response_code), search_term(search_term), @@ -53,6 +57,8 @@ caption(caption), quick_action_uri(quick_action_uri), quick_action_category(quick_action_category), - logged_event_id(logged_event_id) {} + logged_event_id(logged_event_id), + search_url_full(search_url_full), + search_url_preload(search_url_preload) {} ResolvedSearchTerm::~ResolvedSearchTerm() {}
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.h b/chrome/browser/android/contextualsearch/resolved_search_term.h index 537c1c9..edc8546 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.h +++ b/chrome/browser/android/contextualsearch/resolved_search_term.h
@@ -41,7 +41,9 @@ const std::string& caption, const std::string& quick_action_uri, const QuickActionCategory& quick_action_category, - int64_t logged_event_id); + int64_t logged_event_id, + const std::string& search_url_full, + const std::string& search_url_preload); ~ResolvedSearchTerm(); const bool is_invalid; @@ -60,6 +62,8 @@ const std::string quick_action_uri; const QuickActionCategory quick_action_category; const int64_t logged_event_id; // Often 0. + const std::string search_url_full; + const std::string search_url_preload; DISALLOW_COPY_AND_ASSIGN(ResolvedSearchTerm); };
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc index 20cba72..69f0c95 100644 --- a/chrome/browser/android/download/download_controller.cc +++ b/chrome/browser/android/download/download_controller.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/android/download/download_manager_service.h" #include "chrome/browser/android/download/download_utils.h" #include "chrome/browser/android/tab_android.h" +#include "chrome/browser/download/download_offline_content_provider.h" #include "chrome/browser/download/download_stats.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/offline_pages/android/offline_page_bridge.h" @@ -386,6 +387,10 @@ if (download::AutoResumptionHandler::Get()) download::AutoResumptionHandler::Get()->OnDownloadStarted(download_item); + DownloadUtils::GetDownloadOfflineContentProvider( + content::DownloadItemUtils::GetBrowserContext(download_item)) + ->OnDownloadStarted(download_item); + OnDownloadUpdated(download_item); }
diff --git a/chrome/browser/android/download/download_manager_bridge.cc b/chrome/browser/android/download/download_manager_bridge.cc index e4f494a..a0f7423 100644 --- a/chrome/browser/android/download/download_manager_bridge.cc +++ b/chrome/browser/android/download/download_manager_bridge.cc
@@ -24,14 +24,15 @@ static void JNI_DownloadManagerBridge_OnAddCompletedDownloadDone( JNIEnv* env, jlong callback_id, - jlong download_id) { + jlong download_id, + jboolean can_resolve) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(callback_id); // Convert java long long int to c++ pointer, take ownership. std::unique_ptr<AddCompletedDownloadCallback> cb( reinterpret_cast<AddCompletedDownloadCallback*>(callback_id)); - std::move(*cb).Run(download_id); + std::move(*cb).Run(download_id, can_resolve); } void DownloadManagerBridge::AddCompletedDownload(
diff --git a/chrome/browser/android/download/download_manager_bridge.h b/chrome/browser/android/download/download_manager_bridge.h index 5c87f8c..c726b1d5 100644 --- a/chrome/browser/android/download/download_manager_bridge.h +++ b/chrome/browser/android/download/download_manager_bridge.h
@@ -9,7 +9,7 @@ #include "components/download/public/common/download_item.h" using DownloadItem = download::DownloadItem; -using AddCompletedDownloadCallback = base::OnceCallback<void(int64_t)>; +using AddCompletedDownloadCallback = base::OnceCallback<void(int64_t, bool)>; // This class pairs with DownloadManagerBridge on Java side, that handles all // the android DownloadManager related functionalities. Both classes have only
diff --git a/chrome/browser/android/download/download_utils.cc b/chrome/browser/android/download/download_utils.cc index 27670e0..dc8afe3 100644 --- a/chrome/browser/android/download/download_utils.cc +++ b/chrome/browser/android/download/download_utils.cc
@@ -8,15 +8,21 @@ #include "base/metrics/field_trial_params.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/android/chrome_feature_list.h" +#include "chrome/browser/download/download_offline_content_provider.h" #include "chrome/browser/download/offline_item_utils.h" +#include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" #include "chrome/grit/generated_resources.h" #include "components/download/public/common/download_utils.h" +#include "components/offline_items_collection/core/offline_content_aggregator.h" +#include "content/public/browser/browser_context.h" #include "jni/DownloadUtils_jni.h" #include "ui/base/l10n/l10n_util.h" using base::android::ConvertUTF16ToJavaString; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; +using OfflineContentAggregator = + offline_items_collection::OfflineContentAggregator; namespace { // If received bytes is more than the size limit and resumption will restart @@ -24,6 +30,9 @@ int kDefaultAutoResumptionSizeLimit = 10 * 1024 * 1024; // 10 MB const char kAutoResumptionSizeLimitParamName[] = "AutoResumptionSizeLimit"; +static DownloadOfflineContentProvider* g_download_provider = nullptr; +static DownloadOfflineContentProvider* g_download_provider_incognito = nullptr; + } // namespace static ScopedJavaLocalRef<jstring> JNI_DownloadUtils_GetFailStateMessage( @@ -68,3 +77,30 @@ ? size_limit : kDefaultAutoResumptionSizeLimit; } + +// static +DownloadOfflineContentProvider* +DownloadUtils::GetDownloadOfflineContentProvider( + content::BrowserContext* browser_context) { + OfflineContentAggregator* aggregator = + OfflineContentAggregatorFactory::GetForBrowserContext(browser_context); + bool is_off_the_record = + browser_context ? browser_context->IsOffTheRecord() : false; + + if (!g_download_provider) { + std::string name_space = OfflineContentAggregator::CreateUniqueNameSpace( + OfflineItemUtils::GetDownloadNamespacePrefix(false), false); + g_download_provider = + new DownloadOfflineContentProvider(aggregator, name_space); + } + + if (!g_download_provider_incognito) { + std::string name_space = OfflineContentAggregator::CreateUniqueNameSpace( + OfflineItemUtils::GetDownloadNamespacePrefix(true), true); + g_download_provider_incognito = + new DownloadOfflineContentProvider(aggregator, name_space); + } + + return is_off_the_record ? g_download_provider_incognito + : g_download_provider; +}
diff --git a/chrome/browser/android/download/download_utils.h b/chrome/browser/android/download/download_utils.h index 73c0b27a..4b5f964 100644 --- a/chrome/browser/android/download/download_utils.h +++ b/chrome/browser/android/download/download_utils.h
@@ -7,11 +7,19 @@ #include "base/files/file_path.h" +namespace content { +class BrowserContext; +} + +class DownloadOfflineContentProvider; + // Native side of DownloadUtils.java. class DownloadUtils { public: static base::FilePath GetUriStringForPath(const base::FilePath& file_path); static int GetAutoResumptionSizeLimit(); + static DownloadOfflineContentProvider* GetDownloadOfflineContentProvider( + content::BrowserContext* browser_context); }; #endif // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_UTILS_H_
diff --git a/chrome/browser/android/explore_sites/blacklist_site_task_unittest.cc b/chrome/browser/android/explore_sites/blacklist_site_task_unittest.cc index f760629..6d4cf4e 100644 --- a/chrome/browser/android/explore_sites/blacklist_site_task_unittest.cc +++ b/chrome/browser/android/explore_sites/blacklist_site_task_unittest.cc
@@ -21,6 +21,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; const char kGoogleUrl[] = "https://www.google.com"; @@ -77,7 +78,8 @@ } TEST_F(ExploreSitesBlacklistSiteTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); BlacklistSiteTask task(store(), kGoogleUrl); RunTask(&task);
diff --git a/chrome/browser/android/explore_sites/clear_activities_task_unittest.cc b/chrome/browser/android/explore_sites/clear_activities_task_unittest.cc index 5feb9187..2e0568e5 100644 --- a/chrome/browser/android/explore_sites/clear_activities_task_unittest.cc +++ b/chrome/browser/android/explore_sites/clear_activities_task_unittest.cc
@@ -24,6 +24,7 @@ namespace explore_sites { namespace { +using InitializationStatus = ExploreSitesStore::InitializationStatus; const char kInsertActivitySql[] = "INSERT INTO activity (time, category_type, url) VALUES (?, ?, ?);"; @@ -151,7 +152,8 @@ } TEST_F(ClearActivitiesTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); ClearActivities(kJanuary2017, kJune2017); // A database failure should be completed but return with an error.
diff --git a/chrome/browser/android/explore_sites/clear_catalog_task_unittest.cc b/chrome/browser/android/explore_sites/clear_catalog_task_unittest.cc index bc38706..093038a 100644 --- a/chrome/browser/android/explore_sites/clear_catalog_task_unittest.cc +++ b/chrome/browser/android/explore_sites/clear_catalog_task_unittest.cc
@@ -124,7 +124,8 @@ }; TEST_F(ExploreSitesClearCatalogTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting( + ExploreSitesStore::InitializationStatus::kFailure, false); // A database failure should be completed but return with an error. EXPECT_FALSE(RunTaskWithResult());
diff --git a/chrome/browser/android/explore_sites/explore_sites_store.cc b/chrome/browser/android/explore_sites/explore_sites_store.cc index a023e983..b3887d3 100644 --- a/chrome/browser/android/explore_sites/explore_sites_store.cc +++ b/chrome/browser/android/explore_sites/explore_sites_store.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/android/explore_sites/explore_sites_store.h" +#include <utility> + #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -20,53 +22,10 @@ namespace explore_sites { namespace { +using offline_pages::SqlStoreBase; const char kExploreSitesStoreFileName[] = "ExploreSitesStore.db"; -bool PrepareDirectory(const base::FilePath& path) { - base::File::Error error = base::File::FILE_OK; - if (!base::DirectoryExists(path.DirName())) { - if (!base::CreateDirectoryAndGetError(path.DirName(), &error)) { - LOG(ERROR) << "Failed to create explore sites db directory: " - << base::File::ErrorToString(error); - return false; - } - } - return true; -} - -bool InitializeSync(sql::Database* db, - const base::FilePath& path, - bool in_memory) { - // These values are default. - db->set_page_size(4096); - db->set_cache_size(500); - db->set_histogram_tag("ExploreSitesStore"); - db->set_exclusive_locking(); - - if (!in_memory && !PrepareDirectory(path)) - return false; - - bool open_db_result = in_memory ? db->OpenInMemory() : db->Open(path); - - if (!open_db_result) { - LOG(ERROR) << "Failed to open database, in memory: " << in_memory; - return false; - } - db->Preload(); - - return ExploreSitesSchema::CreateOrUpgradeIfNeeded(db); -} - -void CloseDatabaseSync( - sql::Database* db, - scoped_refptr<base::SingleThreadTaskRunner> callback_runner, - base::OnceClosure callback) { - if (db) - db->Close(); - callback_runner->PostTask(FROM_HERE, std::move(callback)); -} - // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. enum class ExploreSitesStoreEvent { @@ -83,107 +42,77 @@ } // namespace -// static -constexpr base::TimeDelta ExploreSitesStore::kClosingDelay; - ExploreSitesStore::ExploreSitesStore( scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) - : blocking_task_runner_(std::move(blocking_task_runner)), - in_memory_(true), - db_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)), - initialization_status_(InitializationStatus::NOT_INITIALIZED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("ExploreSitesStore", + std::move(blocking_task_runner), + base::FilePath()) {} ExploreSitesStore::ExploreSitesStore( scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, const base::FilePath& path) - : blocking_task_runner_(std::move(blocking_task_runner)), - db_file_path_(path.AppendASCII(kExploreSitesStoreFileName)), - in_memory_(false), - db_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)), - initialization_status_(InitializationStatus::NOT_INITIALIZED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("ExploreSitesStore", + std::move(blocking_task_runner), + path.AppendASCII(kExploreSitesStoreFileName)) {} ExploreSitesStore::~ExploreSitesStore() {} -void ExploreSitesStore::SetInitializationStatusForTest( - InitializationStatus status) { - initialization_status_ = status; +base::OnceCallback<bool(sql::Database* db)> +ExploreSitesStore::GetSchemaInitializationFunction() { + return base::BindOnce(&ExploreSitesSchema::CreateOrUpgradeIfNeeded); } -void ExploreSitesStore::Initialize(base::OnceClosure pending_command) { +void ExploreSitesStore::OnOpenStart(base::TimeTicks last_closing_time) { TRACE_EVENT_ASYNC_BEGIN1("explore_sites", "ExploreSitesStore", this, - "is reopen", !last_closing_time_.is_null()); - DCHECK_EQ(initialization_status_, InitializationStatus::NOT_INITIALIZED); - initialization_status_ = InitializationStatus::INITIALIZING; - - if (!last_closing_time_.is_null()) { + "is reopen", !last_closing_time.is_null()); + if (!last_closing_time.is_null()) { ReportStoreEvent(ExploreSitesStoreEvent::kReopened); } else { ReportStoreEvent(ExploreSitesStoreEvent::kOpenedFirstTime); } - - // This is how we reset a pointer and provide deleter. This is necessary to - // ensure that we can close the store more than once. - db_ = DatabaseUniquePtr(new sql::Database, - base::OnTaskRunnerDeleter(blocking_task_runner_)); - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&InitializeSync, db_.get(), db_file_path_, in_memory_), - base::BindOnce(&ExploreSitesStore::OnInitializeDone, - weak_ptr_factory_.GetWeakPtr(), - std::move(pending_command))); } -void ExploreSitesStore::OnInitializeDone(base::OnceClosure pending_command, - bool success) { - // TODO(carlosk): Add initializing error reporting here. +void ExploreSitesStore::OnOpenDone(bool success) { TRACE_EVENT_ASYNC_STEP_PAST1("explore_sites", "ExploreSitesStore", this, "Initializing", "succeeded", success); - DCHECK_EQ(initialization_status_, InitializationStatus::INITIALIZING); - if (success) { - initialization_status_ = InitializationStatus::SUCCESS; - } else { - initialization_status_ = InitializationStatus::FAILURE; - db_.reset(); + if (!success) { TRACE_EVENT_ASYNC_END0("explore_sites", "ExploreSitesStore", this); } - - CHECK(!pending_command.is_null()); - std::move(pending_command).Run(); - - // Once pending commands are empty, we get back to NOT_INITIALIZED state, to - // make it possible to retry initialization next time a DB operation is - // attempted. - if (initialization_status_ == InitializationStatus::FAILURE) - initialization_status_ = InitializationStatus::NOT_INITIALIZED; } -void ExploreSitesStore::CloseInternal() { - if (initialization_status_ != InitializationStatus::SUCCESS) { +void ExploreSitesStore::OnTaskBegin(bool is_initialized) { + TRACE_EVENT_ASYNC_BEGIN1("explore_sites", + "ExploreSites Store: task execution", this, + "is store loaded", is_initialized); +} + +void ExploreSitesStore::OnTaskRunComplete() { + // Note: the time recorded for this trace step will include thread hop wait + // times to the background thread and back. + TRACE_EVENT_ASYNC_STEP_PAST0( + "explore_sites", "ExploreSites Store: task execution", this, "Task"); +} + +void ExploreSitesStore::OnTaskReturnComplete() { + TRACE_EVENT_ASYNC_STEP_PAST0( + "explore_sites", "ExploreSites Store: task execution", this, "Callback"); + TRACE_EVENT_ASYNC_END0("explore_sites", "ExploreSites Store: task execution", + this); +} + +void ExploreSitesStore::OnCloseStart( + InitializationStatus initialization_status) { + if (initialization_status != InitializationStatus::kSuccess) { ReportStoreEvent(ExploreSitesStoreEvent::kCloseSkipped); return; } TRACE_EVENT_ASYNC_STEP_PAST0("explore_sites", "ExploreSitesStore", this, "Open"); - last_closing_time_ = offline_pages::OfflineTimeNow(); ReportStoreEvent(ExploreSitesStoreEvent::kClosed); - - initialization_status_ = InitializationStatus::NOT_INITIALIZED; - blocking_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &CloseDatabaseSync, db_.get(), base::ThreadTaskRunnerHandle::Get(), - base::BindOnce(&ExploreSitesStore::CloseInternalDone, - weak_ptr_factory_.GetWeakPtr(), std::move(db_)))); } -void ExploreSitesStore::CloseInternalDone(DatabaseUniquePtr db) { - db.reset(); +void ExploreSitesStore::OnCloseComplete() { TRACE_EVENT_ASYNC_STEP_PAST0("explore_sites", "ExploreSitesStore", this, "Closing"); TRACE_EVENT_ASYNC_END0("explore_sites", "ExploreSitesStore", this);
diff --git a/chrome/browser/android/explore_sites/explore_sites_store.h b/chrome/browser/android/explore_sites/explore_sites_store.h index 3a6a354c..a68a13c 100644 --- a/chrome/browser/android/explore_sites/explore_sites_store.h +++ b/chrome/browser/android/explore_sites/explore_sites_store.h
@@ -16,6 +16,7 @@ #include "base/task_runner_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "components/offline_pages/task/sql_store_base.h" namespace sql { class Database; @@ -23,36 +24,14 @@ namespace explore_sites { -enum class InitializationStatus { - NOT_INITIALIZED, - INITIALIZING, - SUCCESS, - FAILURE, -}; - // ExploreSitesStore is a front end to SQLite store hosting the explore sites // web catalog. // // The store controls the pointer to the SQLite database and only makes it // available to the |RunCallback| of the |Execute| method on the blocking // thread. -class ExploreSitesStore { +class ExploreSitesStore : public offline_pages::SqlStoreBase { public: - // Definition of the callback that is going to run the core of the command in - // the |Execute| method. - template <typename T> - using RunCallback = base::OnceCallback<T(sql::Database*)>; - - // Definition of the callback used to pass the result back to the caller of - // |Execute| method. - template <typename T> - using ResultCallback = base::OnceCallback<void(T)>; - - // Defines inactivity time of DB after which it is going to be closed. - // TODO(dewittj): Derive appropriate value in a scientific way. - static constexpr base::TimeDelta kClosingDelay = - base::TimeDelta::FromSeconds(20); - // Creates an instance of |ExploreSitesStore| with an in-memory SQLite // database. explicit ExploreSitesStore( @@ -64,121 +43,19 @@ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, const base::FilePath& database_dir); - ~ExploreSitesStore(); + ~ExploreSitesStore() override; - // Executes a |run_callback| on SQL store on the blocking thread, and posts - // its result back to calling thread through |result_callback|. - // Calling |Execute| when store is NOT_INITIALIZED will cause the store - // initialization to start. - // Store initialization status needs to be SUCCESS for run_callback to run. - // If initialization fails, |result_callback| is invoked with |default_value|. - template <typename T> - void Execute(RunCallback<T> run_callback, - ResultCallback<T> result_callback, - T default_value) { - CHECK_NE(initialization_status_, InitializationStatus::INITIALIZING); - - if (initialization_status_ == InitializationStatus::NOT_INITIALIZED) { - Initialize(base::BindOnce( - &ExploreSitesStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(), - std::move(run_callback), std::move(result_callback), - std::move(default_value))); - return; - } - - TRACE_EVENT_ASYNC_BEGIN1( - "explore_sites", "ExploreSites Store: task execution", this, - "is store loaded", - initialization_status_ == InitializationStatus::SUCCESS); - // Ensure that any scheduled close operations are canceled. - closing_weak_ptr_factory_.InvalidateWeakPtrs(); - - sql::Database* db = initialization_status_ == InitializationStatus::SUCCESS - ? db_.get() - : nullptr; - if (!db) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(result_callback), std::move(default_value))); - } else { - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(std::move(run_callback), db), - base::BindOnce(&ExploreSitesStore::RescheduleClosing<T>, - weak_ptr_factory_.GetWeakPtr(), - std::move(result_callback))); - } - } - - // Gets the initialization status of the store. - InitializationStatus initialization_status() const { - return initialization_status_; - } - - void SetInitializationStatusForTest(InitializationStatus status); - - private: - using DatabaseUniquePtr = - std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter>; - - // Used internally to initialize connection. - void Initialize(base::OnceClosure pending_command); - - // Used to conclude opening/resetting DB connection. - void OnInitializeDone(base::OnceClosure pending_command, bool success); - - // Reschedules the closing with a delay. Ensures that |result_callback| is - // called. - template <typename T> - void RescheduleClosing(ResultCallback<T> result_callback, T result) { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&ExploreSitesStore::CloseInternal, - closing_weak_ptr_factory_.GetWeakPtr()), - kClosingDelay); - - // Note: the time recorded for this trace step will include thread hop wait - // times to the background thread and back. - TRACE_EVENT_ASYNC_STEP_PAST0( - "explore_sites", "ExploreSites Store: task execution", this, "Task"); - std::move(result_callback).Run(std::move(result)); - TRACE_EVENT_ASYNC_STEP_PAST0("explore_sites", - "ExploreSites Store: task execution", this, - "Callback"); - TRACE_EVENT_ASYNC_END0("explore_sites", - "ExploreSites Store: task execution", this); - } - - // Internal function initiating the closing. - void CloseInternal(); - - // Completes the closing. Main purpose is to destroy the db pointer. - void CloseInternalDone(DatabaseUniquePtr db); - - // Background thread where all SQL access should be run. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - - // Path to the database on disk. - base::FilePath db_file_path_; - - // Only open the store in memory. Used for testing. - bool in_memory_; - - // Database connection. - std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter> db_; - - // Initialization status of the store. - InitializationStatus initialization_status_; - - // Time of the last time the store was closed. Kept for metrics reporting. - base::Time last_closing_time_; - - // Weak pointer to control the callback. - base::WeakPtrFactory<ExploreSitesStore> weak_ptr_factory_; - // Weak pointer to cancel closing of the store. - base::WeakPtrFactory<ExploreSitesStore> closing_weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ExploreSitesStore); + protected: + // SqlStoreBase: + base::OnceCallback<bool(sql::Database* db)> GetSchemaInitializationFunction() + override; + void OnOpenStart(base::TimeTicks last_open_time) override; + void OnOpenDone(bool success) override; + void OnTaskBegin(bool is_initialized) override; + void OnTaskRunComplete() override; + void OnTaskReturnComplete() override; + void OnCloseStart(InitializationStatus status_before_close) override; + void OnCloseComplete() override; }; } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_store_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_store_unittest.cc index 49494ccb..dabb0a5 100644 --- a/chrome/browser/android/explore_sites/explore_sites_store_unittest.cc +++ b/chrome/browser/android/explore_sites/explore_sites_store_unittest.cc
@@ -24,6 +24,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; class ExploreSitesStoreTest : public testing::Test { public: @@ -88,7 +89,8 @@ base::BindLambdaForTesting([&](sql::Database* db) { return true; }); bool result = ExecuteSync<bool>(store.get(), run_callback, false); EXPECT_TRUE(result); - EXPECT_EQ(InitializationStatus::SUCCESS, store->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store->initialization_status_for_testing()); } TEST_F(ExploreSitesStoreTest, StoreCloses) { @@ -103,13 +105,14 @@ FastForwardBy(ExploreSitesStore::kClosingDelay); PumpLoop(); - EXPECT_EQ(InitializationStatus::NOT_INITIALIZED, - store->initialization_status()); + EXPECT_EQ(InitializationStatus::kNotInitialized, + store->initialization_status_for_testing()); // Executing something causes initialization. ExecuteSync<bool>(store.get(), run_callback, false); - EXPECT_EQ(InitializationStatus::SUCCESS, store->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store->initialization_status_for_testing()); } } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/get_catalog_task_unittest.cc b/chrome/browser/android/explore_sites/get_catalog_task_unittest.cc index c669a55..9f10865 100644 --- a/chrome/browser/android/explore_sites/get_catalog_task_unittest.cc +++ b/chrome/browser/android/explore_sites/get_catalog_task_unittest.cc
@@ -24,6 +24,7 @@ namespace explore_sites { namespace { +using InitializationStatus = ExploreSitesStore::InitializationStatus; void ValidateTestingCatalog(GetCatalogTask::CategoryList* catalog) { EXPECT_FALSE(catalog == nullptr); @@ -271,7 +272,8 @@ } TEST_F(ExploreSitesGetCatalogTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); GetCatalogTask task(store(), false, base::BindOnce(&ExpectFailedGetCatalogResult));
diff --git a/chrome/browser/android/explore_sites/get_images_task_unittest.cc b/chrome/browser/android/explore_sites/get_images_task_unittest.cc index cd4af90..df6cdaa 100644 --- a/chrome/browser/android/explore_sites/get_images_task_unittest.cc +++ b/chrome/browser/android/explore_sites/get_images_task_unittest.cc
@@ -22,6 +22,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; class ExploreSitesGetImagesTaskTest : public TaskTestBase { public: @@ -89,7 +90,8 @@ } TEST_F(ExploreSitesGetImagesTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); GetImagesTask task(store(), 1, StoreResult()); RunTask(&task);
diff --git a/chrome/browser/android/explore_sites/get_version_task_unittest.cc b/chrome/browser/android/explore_sites/get_version_task_unittest.cc index 8e8f323..d880a4b 100644 --- a/chrome/browser/android/explore_sites/get_version_task_unittest.cc +++ b/chrome/browser/android/explore_sites/get_version_task_unittest.cc
@@ -21,6 +21,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; class ExploreSitesGetVersionTaskTest : public TaskTestBase { public: @@ -69,7 +70,8 @@ }; TEST_F(ExploreSitesGetVersionTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); GetVersionTask task(store(), base::BindLambdaForTesting( [&](std::string result) { EXPECT_EQ("", result); }));
diff --git a/chrome/browser/android/explore_sites/history_statistics_reporter.cc b/chrome/browser/android/explore_sites/history_statistics_reporter.cc index 9771da3..65a734c 100644 --- a/chrome/browser/android/explore_sites/history_statistics_reporter.cc +++ b/chrome/browser/android/explore_sites/history_statistics_reporter.cc
@@ -56,7 +56,6 @@ base::Time last_report_time = prefs_->GetTime(kWeeklyStatsReportingTimestamp); if (last_report_time > clock_->Now() - base::TimeDelta::FromDays(7)) return; - prefs_->SetTime(kWeeklyStatsReportingTimestamp, clock_->Now()); base::TimeDelta computeStatisticsDelay = base::TimeDelta::FromSeconds(kComputeStatisticsDelaySeconds); @@ -103,5 +102,7 @@ if (!result.success) return; UMA_HISTOGRAM_COUNTS_1000("ExploreSites.MonthlyHostCount", result.count); + // Remember when stats were reported to skip attempts until next week. + prefs_->SetTime(kWeeklyStatsReportingTimestamp, clock_->Now()); } } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/history_statistics_reporter_unittest.cc b/chrome/browser/android/explore_sites/history_statistics_reporter_unittest.cc index a8a4ee8..621f76ea 100644 --- a/chrome/browser/android/explore_sites/history_statistics_reporter_unittest.cc +++ b/chrome/browser/android/explore_sites/history_statistics_reporter_unittest.cc
@@ -192,8 +192,6 @@ } TEST_F(HistoryStatisticsReporterTest, OneRunPerWeekSaveTimestamp) { - base::Time time_now = task_runner()->GetMockClock()->Now(); - ASSERT_TRUE(LoadHistory()); ScheduleReportAndRunUntilIdle(); @@ -202,6 +200,7 @@ histograms().ExpectTotalCount("History.DatabaseMonthlyHostCountTime", 1); // Reporter should have left the time of request in Prefs. + base::Time time_now = task_runner()->GetMockClock()->Now(); EXPECT_EQ(time_now, prefs()->GetTime(kWeeklyStatsReportingTimestamp)); } @@ -217,8 +216,6 @@ } TEST_F(HistoryStatisticsReporterTest, OneRunPerWeekReadTimestampAfterWeek) { - base::Time time_now = task_runner()->GetMockClock()->Now(); - ASSERT_TRUE(LoadHistory()); prefs()->SetTime( @@ -229,6 +226,7 @@ // More than a week since last query, should have gone through. histograms().ExpectTotalCount("History.DatabaseMonthlyHostCountTime", 1); // Reporter should have left the time of request in Prefs. + base::Time time_now = task_runner()->GetMockClock()->Now(); EXPECT_EQ(time_now, prefs()->GetTime(kWeeklyStatsReportingTimestamp)); }
diff --git a/chrome/browser/android/explore_sites/import_catalog_task_unittest.cc b/chrome/browser/android/explore_sites/import_catalog_task_unittest.cc index dc5cc6e..f367ae0 100644 --- a/chrome/browser/android/explore_sites/import_catalog_task_unittest.cc +++ b/chrome/browser/android/explore_sites/import_catalog_task_unittest.cc
@@ -23,6 +23,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; const char kVersionToken[] = "12345"; const char kGoogleUrl[] = "https://www.google.com"; @@ -82,7 +83,8 @@ }; TEST_F(ExploreSitesImportCatalogTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); ImportCatalogTask task( store(), kVersionToken, std::make_unique<Catalog>(), base::BindOnce(&ExploreSitesImportCatalogTaskTest::OnImportTaskDone,
diff --git a/chrome/browser/android/explore_sites/increment_shown_count_task_unittest.cc b/chrome/browser/android/explore_sites/increment_shown_count_task_unittest.cc index ef061f2..4a58908 100644 --- a/chrome/browser/android/explore_sites/increment_shown_count_task_unittest.cc +++ b/chrome/browser/android/explore_sites/increment_shown_count_task_unittest.cc
@@ -17,7 +17,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { - +using InitializationStatus = ExploreSitesStore::InitializationStatus; class ExploreSitesIncrementShownCountTaskTest : public TaskTestBase { public: ExploreSitesIncrementShownCountTaskTest() = default; @@ -71,7 +71,8 @@ } TEST_F(ExploreSitesIncrementShownCountTaskTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); IncrementShownCountTask task(store(), 1); RunTask(&task);
diff --git a/chrome/browser/android/explore_sites/record_site_click_task_unittest.cc b/chrome/browser/android/explore_sites/record_site_click_task_unittest.cc index c3b33f5..a659ec6 100644 --- a/chrome/browser/android/explore_sites/record_site_click_task_unittest.cc +++ b/chrome/browser/android/explore_sites/record_site_click_task_unittest.cc
@@ -19,6 +19,7 @@ using offline_pages::TaskTestBase; namespace explore_sites { +using InitializationStatus = ExploreSitesStore::InitializationStatus; const char kUrl[] = "https://www.example.com"; const int kType = 5; @@ -70,7 +71,8 @@ } TEST_F(ExploreSitesRecordSiteClickTest, StoreFailure) { - store()->SetInitializationStatusForTest(InitializationStatus::FAILURE); + store()->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); RecordSiteClickTask task(store(), kUrl, kType); RunTask(&task);
diff --git a/chrome/browser/android/feed/feed_logging_bridge.cc b/chrome/browser/android/feed/feed_logging_bridge.cc index 34877dc..18a0a0f 100644 --- a/chrome/browser/android/feed/feed_logging_bridge.cc +++ b/chrome/browser/android/feed/feed_logging_bridge.cc
@@ -171,6 +171,54 @@ feed_logging_metrics_->OnPietFrameRenderingEvent(std::move(piet_error_codes)); } +void FeedLoggingBridge::OnInternalError(JNIEnv* j_env, + const JavaRef<jobject>& j_this, + const jint j_internal_error) { + feed_logging_metrics_->OnInternalError(j_internal_error); +} + +void FeedLoggingBridge::OnTokenCompleted( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jboolean j_was_synthetic, + const jint j_content_count, + const jint j_token_count) { + feed_logging_metrics_->OnTokenCompleted(j_was_synthetic, j_content_count, + j_token_count); +} + +void FeedLoggingBridge::OnTokenFailedToComplete( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jboolean j_was_synthetic, + const jint j_failure_count) { + feed_logging_metrics_->OnTokenFailedToComplete(j_was_synthetic, + j_failure_count); +} + +void FeedLoggingBridge::OnServerRequest( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_request_reason) { + feed_logging_metrics_->OnServerRequest(j_request_reason); +} + +void FeedLoggingBridge::OnZeroStateShown( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_zero_state_show_reason) { + feed_logging_metrics_->OnZeroStateShown(j_zero_state_show_reason); +} + +void FeedLoggingBridge::OnZeroStateRefreshCompleted( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_new_content_count, + const jint j_new_token_count) { + feed_logging_metrics_->OnZeroStateRefreshCompleted(j_new_content_count, + j_new_token_count); +} + void FeedLoggingBridge::OnContentTargetVisited(JNIEnv* j_env, const JavaRef<jobject>& j_this, const jlong visit_time_ms,
diff --git a/chrome/browser/android/feed/feed_logging_bridge.h b/chrome/browser/android/feed/feed_logging_bridge.h index 2f51994..344dd643 100644 --- a/chrome/browser/android/feed/feed_logging_bridge.h +++ b/chrome/browser/android/feed/feed_logging_bridge.h
@@ -102,6 +102,35 @@ const base::android::JavaRef<jobject>& j_this, const base::android::JavaRef<jintArray>& j_piet_error_codes); + void OnInternalError(JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_internal_error); + + void OnTokenCompleted(JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jboolean j_was_synthetic, + const jint j_content_count, + const jint j_token_count); + + void OnTokenFailedToComplete(JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jboolean j_was_synthetic, + const jint j_failure_count); + + void OnServerRequest(JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_request_reason); + + void OnZeroStateShown(JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_zero_state_show_reason); + + void OnZeroStateRefreshCompleted( + JNIEnv* j_env, + const base::android::JavaRef<jobject>& j_this, + const jint j_new_content_count, + const jint j_new_token_count); + void OnContentTargetVisited(JNIEnv* j_env, const base::android::JavaRef<jobject>& j_this, const jlong visit_time_ms,
diff --git a/chrome/browser/android/profiles/profile_downloader_android.cc b/chrome/browser/android/profiles/profile_downloader_android.cc index 8dbe433..0e84f7e 100644 --- a/chrome/browser/android/profiles/profile_downloader_android.cc +++ b/chrome/browser/android/profiles/profile_downloader_android.cc
@@ -168,8 +168,8 @@ GetProfileAttributesWithPath(profile->GetPath(), &entry)) { gfx::Image avatar_image = entry->GetAvatarIcon(); if (!avatar_image.IsEmpty() && - avatar_image.Width() > profiles::kAvatarIconWidth && - avatar_image.Height() > profiles::kAvatarIconHeight && + avatar_image.Width() > profiles::kAvatarIconSize && + avatar_image.Height() > profiles::kAvatarIconSize && avatar_image.AsImageSkia().bitmap()) { jbitmap = gfx::ConvertToJavaBitmap(avatar_image.AsImageSkia().bitmap()); }
diff --git a/chrome/browser/android/send_tab_to_self/OWNERS b/chrome/browser/android/send_tab_to_self/OWNERS new file mode 100644 index 0000000..e58f618d --- /dev/null +++ b/chrome/browser/android/send_tab_to_self/OWNERS
@@ -0,0 +1,3 @@ +file://components/send_tab_to_self/OWNERS + +# COMPONENT: UI>Browser>Sharing
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc index 95d0d75b..d305c2e3 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.cc +++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -14,6 +14,7 @@ #include "base/command_line.h" #include "base/metrics/histogram_macros.h" #include "base/optional.h" +#include "base/rand_util.h" #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/feature_utilities.h" #include "chrome/browser/android/hung_renderer_infobar_delegate.h" @@ -495,13 +496,18 @@ void JNI_TabWebContentsDelegateAndroid_OnRendererUnresponsive( JNIEnv* env, const JavaParamRef<jobject>& java_web_contents) { + // Rate limit the number of stack dumps so we don't overwhelm our crash + // reports. + content::WebContents* web_contents = + content::WebContents::FromJavaWebContents(java_web_contents); + if (base::RandDouble() < 0.01) + web_contents->GetMainFrame()->GetProcess()->DumpProcessStack(); + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableHungRendererInfoBar)) { return; } - content::WebContents* web_contents = - content::WebContents::FromJavaWebContents(java_web_contents); InfoBarService* infobar_service = InfoBarService::FromWebContents(web_contents); DCHECK(!FindHungRendererInfoBar(infobar_service));
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc index 33aaa1b..638359da3 100644 --- a/chrome/browser/background_fetch/background_fetch_browsertest.cc +++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -6,7 +6,6 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/command_line.h" #include "base/logging.h" #include "base/run_loop.h" #include "base/strings/string_util.h" @@ -229,12 +228,6 @@ std::make_unique<OfflineContentProviderObserver>()) {} ~BackgroundFetchBrowserTest() override = default; - void SetUpCommandLine(base::CommandLine* command_line) override { - // Background Fetch is available as an experimental Web Platform feature. - command_line->AppendSwitch( - switches::kEnableExperimentalWebPlatformFeatures); - } - void SetUpOnMainThread() override { https_server_ = std::make_unique<net::EmbeddedTestServer>( net::EmbeddedTestServer::TYPE_HTTPS);
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 099ca237..05d6fa88 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -482,11 +482,16 @@ <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_JS" file="resources\signin\signin_email_confirmation\signin_email_confirmation.js" type="BINDATA" /> <include name="IDR_SIGNIN_ERROR_HTML" file="resources\signin\signin_error\signin_error.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_SIGNIN_ERROR_JS" file="resources\signin\signin_error\signin_error.js" type="BINDATA" /> + <include name="IDR_USB_DEVICE_ENUMERATION_OPTIONS_MOJOM_LITE_JS" file="${root_gen_dir}\device\usb\public\mojom\device_enumeration_options.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_DEVICE_MANAGER_CLIENT_MOJOM_LITE_JS" file="${root_gen_dir}\device\usb\public\mojom\device_manager_client.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_DEVICE_MANAGER_MOJOM_LITE_JS" file="${root_gen_dir}\device\usb\public\mojom\device_manager.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_DEVICE_MANAGER_TEST_MOJOM_LITE_JS" file="${root_gen_dir}\device\usb\public\mojom\device_manager_test.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_DEVICE_MOJOM_LITE_JS" file="${root_gen_dir}\device\usb\public\mojom\device.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> <include name="IDR_USB_INTERNALS_CSS" file="resources\usb_internals\usb_internals.css" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_INTERNALS_DEVICES_PAGE_JS" file="resources\usb_internals\devices_page.js" type="BINDATA" compress="gzip" /> <include name="IDR_USB_INTERNALS_HTML" file="resources\usb_internals\usb_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> <include name="IDR_USB_INTERNALS_JS" file="resources\usb_internals\usb_internals.js" type="BINDATA" compress="gzip" /> - <include name="IDR_USB_INTERNALS_MOJO_JS" file="${root_gen_dir}\chrome\browser\ui\webui\usb_internals\usb_internals.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> - <include name="IDR_USB_DEVICE_MANAGER_TEST_MOJO_JS" file="${root_gen_dir}\device\usb\public\mojom\device_manager_test.mojom-lite.js" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_USB_INTERNALS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\ui\webui\usb_internals\usb_internals.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_WEBRTC_LOGS_HTML" file="resources\media\webrtc_logs.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_WEBRTC_LOGS_JS" file="resources\media\webrtc_logs.js" type="BINDATA" /> <include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 8bfd708e..4a65579 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4203,7 +4203,7 @@ throttles.push_back(std::move(background_tab_navigation_throttle)); #endif -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) std::unique_ptr<content::NavigationThrottle> password_protection_navigation_throttle = safe_browsing::MaybeCreateNavigationThrottle(handle);
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc index 9fe5909..f25ff94 100644 --- a/chrome/browser/chrome_navigation_browsertest.cc +++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -35,6 +35,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/site_isolation_policy.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -1400,3 +1401,71 @@ content::WaitForLoadStop(main_contents); ASSERT_EQ(GURL("about:blank"), main_contents->GetLastCommittedURL()); } + +// This test class turns on the mode where sites where the user enters a +// password are dynamically added to the list of sites requiring a dedicated +// process. It also disables strict site isolation so that the effects of +// password isolation can be observed. +class SiteIsolationForPasswordSitesBrowserTest + : public ChromeNavigationBrowserTest { + protected: + void SetUp() override { + feature_list_.InitWithFeatures({features::kSiteIsolationForPasswordSites}, + {features::kSitePerProcess}); + ChromeNavigationBrowserTest::SetUp(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Verifies that a site gets process-isolated after a password is typed on a +// page from that site. +IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest, + SiteIsIsolatedAfterEnteringPassword) { + // This test requires dynamic isolated origins to be enabled. + if (!content::SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled()) + return; + + GURL url(embedded_test_server()->GetURL("sub.foo.com", + "/password/password_form.html")); + ui_test_utils::NavigateToURL(browser(), url); + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // foo.com should not be isolated to start with. Verify that a cross-site + // iframe does not become an OOPIF. + std::string kAppendIframe = R"( + var i = document.createElement('iframe'); + i.id = 'child'; + document.body.appendChild(i);)"; + EXPECT_TRUE(ExecJs(contents, kAppendIframe)); + GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html")); + EXPECT_TRUE(NavigateIframeToURL(contents, "child", bar_url)); + content::RenderFrameHost* child = ChildFrameAt(contents->GetMainFrame(), 0); + EXPECT_FALSE(child->IsCrossProcessSubframe()); + + // Fill a form and submit through a <input type="submit"> button. + content::TestNavigationObserver observer(contents); + std::string kFillAndSubmit = + "document.getElementById('username_field').value = 'temp';" + "document.getElementById('password_field').value = 'random';" + "document.getElementById('input_submit_button').click()"; + EXPECT_TRUE(content::ExecJs(contents, kFillAndSubmit)); + observer.Wait(); + + // Open a fresh tab (forcing a new BrowsingInstance), navigate to foo.com, + // and verify that a cross-site iframe now becomes an OOPIF. + AddBlankTabAndShow(browser()); + EXPECT_EQ(2, browser()->tab_strip_model()->count()); + content::WebContents* new_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_NE(new_contents, contents); + + ui_test_utils::NavigateToURL(browser(), url); + EXPECT_TRUE(ExecJs(new_contents, kAppendIframe)); + EXPECT_TRUE(NavigateIframeToURL(new_contents, "child", bar_url)); + content::RenderFrameHost* new_child = + ChildFrameAt(new_contents->GetMainFrame(), 0); + EXPECT_TRUE(new_child->IsCrossProcessSubframe()); +}
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 9b5206c..34f999b 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -972,8 +972,8 @@ "fileapi/mtp_watcher_manager.h", "fileapi/recent_arc_media_source.cc", "fileapi/recent_arc_media_source.h", - "fileapi/recent_download_source.cc", - "fileapi/recent_download_source.h", + "fileapi/recent_disk_source.cc", + "fileapi/recent_disk_source.h", "fileapi/recent_drive_source.cc", "fileapi/recent_drive_source.h", "fileapi/recent_file.cc", @@ -2338,7 +2338,7 @@ "fileapi/file_access_permissions_unittest.cc", "fileapi/file_system_backend_unittest.cc", "fileapi/recent_arc_media_source_unittest.cc", - "fileapi/recent_download_source_unittest.cc", + "fileapi/recent_disk_source_unittest.cc", "fileapi/recent_model_unittest.cc", "fileapi/test/fake_recent_source.cc", "hats/hats_finch_helper_unittest.cc", @@ -2587,7 +2587,6 @@ ":arc_test_support", ":attestation_proto", ":test_support", - ":time_limit_tests", ":user_activity_event_proto", "//ash", "//ash/system/message_center/arc:test_support", @@ -2758,37 +2757,3 @@ seed_corpus = "smb_client/fuzzer_data/smb_url_corpus" } - -# Build target related to the time limit processor tests. Must be kept -# separated from the other unit tests because it is the only one allowed -# to use the :protobuf_full dependency. -source_set("time_limit_tests") { - testonly = true - check_includes = false - - sources = [ - "child_accounts/time_limit_consistency_test/consistency_golden_converter.cc", - "child_accounts/time_limit_consistency_test/consistency_golden_converter_unittest.cc", - "child_accounts/time_limit_consistency_test/consistency_golden_loader.cc", - "child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc", - ] - deps = [ - ":chromeos", - ":consistency_golden_proto", - "//base", - "//testing/gmock", - "//testing/gtest", - "//third_party/protobuf:protobuf_full", - ] - data = [ - "child_accounts/time_limit_consistency_test/goldens/", - "child_accounts/time_limit_consistency_test/test_goldens/", - ] -} - -proto_library("consistency_golden_proto") { - sources = [ - "child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto", - ] - generate_python = false -}
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc index 46696ae9..6556008 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -54,6 +54,8 @@ constexpr char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse"; +bool ignore_kiosk_app_data_load_failures_for_testing = false; + // Returns true for valid kiosk app manifest. bool IsValidKioskAppManifest(const extensions::Manifest& manifest) { bool kiosk_enabled; @@ -106,7 +108,7 @@ } private: - ~CrxLoader() override {} + ~CrxLoader() override = default; // extensions::SandboxedUnpackerClient void OnUnpackSuccess( @@ -213,7 +215,7 @@ private: friend class base::RefCounted<WebstoreDataParser>; - ~WebstoreDataParser() override {} + ~WebstoreDataParser() override = default; void ReportFailure() { if (client_) @@ -277,9 +279,14 @@ status_(STATUS_INIT), update_url_(update_url), crx_file_(cached_crx), - weak_factory_(this) {} + weak_factory_(this) { + if (ignore_kiosk_app_data_load_failures_for_testing) { + LOG(WARNING) << "Force KioskAppData loaded for testing."; + SetStatus(STATUS_LOADED); + } +} -KioskAppData::~KioskAppData() {} +KioskAppData::~KioskAppData() = default; void KioskAppData::Load() { SetStatus(STATUS_LOADING); @@ -351,6 +358,12 @@ } void KioskAppData::SetStatus(Status status) { + if (status == STATUS_ERROR && + ignore_kiosk_app_data_load_failures_for_testing) { + LOG(WARNING) << "Ignoring KioskAppData error for testing. Force OK."; + status = STATUS_LOADED; + } + if (status_ == status) return; @@ -445,6 +458,11 @@ StartFetch(); } +// static +void KioskAppData::SetIgnoreKioskAppDataLoadFailuresForTesting(bool value) { + ignore_kiosk_app_data_load_failures_for_testing = value; +} + void KioskAppData::OnWebstoreParseSuccess( const SkBitmap& icon, const std::string& required_platform_version) {
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.h b/chrome/browser/chromeos/app_mode/kiosk_app_data.h index ffe5baea..c1cc646 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.h +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.h
@@ -92,6 +92,10 @@ void OnIconLoadSuccess(const gfx::ImageSkia& icon) override; void OnIconLoadFailure() override; + // Tests do not always fake app data download. + // This allows to ignore download errors. + static void SetIgnoreKioskAppDataLoadFailuresForTesting(bool value); + private: class CrxLoader; class WebstoreDataParser;
diff --git a/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc b/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc index 966c4e1..bfc3f9f 100644 --- a/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc +++ b/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc
@@ -41,6 +41,7 @@ bool IsSpeaking() override { return false; } void SpeakOrEnqueue(content::TtsUtterance* utterance) override {} void Stop() override {} + void Stop(const GURL& source_url) override {} void Pause() override {} void Resume() override {} void GetVoices(content::BrowserContext* browser_context,
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc deleted file mode 100644 index d9b9c5a..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2019 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/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h" - -#include "base/files/dir_reader_posix.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "base/strings/strcat.h" -#include "base/strings/string_util.h" -#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h" -#include "third_party/protobuf/src/google/protobuf/text_format.h" - -namespace chromeos { -namespace time_limit_consistency { -namespace { - -base::FilePath GetGoldensPath() { - base::FilePath path; - base::PathService::Get(base::DIR_SOURCE_ROOT, &path); - - return path.Append( - FILE_PATH_LITERAL("chrome/browser/chromeos/child_accounts/" - "time_limit_consistency_test/goldens")); -} - -} // namespace - -std::vector<GoldenParam> LoadGoldenCases() { - return LoadGoldenCasesFromPath(GetGoldensPath()); -} - -std::vector<GoldenParam> LoadGoldenCasesFromPath( - const base::FilePath& directory_path) { - std::vector<GoldenParam> golden_params_list; - base::DirReaderPosix dir_reader(directory_path.value().c_str()); - - while (dir_reader.Next()) { - if (!base::EndsWith(dir_reader.name(), ".textproto", - base::CompareCase::INSENSITIVE_ASCII)) { - continue; - } - - ConsistencyGolden golden_suite; - base::File golden_file(directory_path.Append(dir_reader.name()), - base::File::FLAG_OPEN | base::File::FLAG_READ); - google::protobuf::io::FileInputStream stream(golden_file.GetPlatformFile()); - google::protobuf::TextFormat::Parse(&stream, &golden_suite); - - // Ignore suites that don't include CHROME_OS as a supported platform. - bool chromeos_supported = - std::count(golden_suite.supported_platforms().begin(), - golden_suite.supported_platforms().end(), CHROME_OS) > 0; - if (!chromeos_supported) - continue; - - std::string suite_name = dir_reader.name(); - base::ReplaceFirstSubstringAfterOffset(&suite_name, 0, ".textproto", ""); - for (int i = 0; i < golden_suite.cases_size(); i++) { - golden_params_list.push_back( - GoldenParam({suite_name, i, golden_suite.cases(i)})); - } - } - - return golden_params_list; -} - -} // namespace time_limit_consistency -} // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h deleted file mode 100644 index a9aac373..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2019 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. -// -// A utility for loading golden files to be used by the time limit processor -// consistency tests. - -#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_ -#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_ - -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.pb.h" - -namespace chromeos { -namespace time_limit_consistency { - -// Holds information for one golden case and metadata used to generate the name -// for its test case (i.e. the name of the golden file it belongs and its index -// inside it). -struct GoldenParam { - const std::string suite_name; - const int index; - const ConsistencyGoldenCase golden_case; -}; - -// Loads all cases from all available golden files into a list of GoldenParams. -std::vector<GoldenParam> LoadGoldenCases(); - -// Loads all cases from all golden files from a given path into a list of -// GoldenParams. LoadGoldenCases() uses this function under the hood. Should not -// be called directly except for testing the golden loader itself. -std::vector<GoldenParam> LoadGoldenCasesFromPath( - const base::FilePath& directory_path); - -} // namespace time_limit_consistency -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc deleted file mode 100644 index b5c7f16..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2019 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/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h" -#include "chrome/browser/chromeos/child_accounts/time_limit_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace chromeos { - -namespace utils = time_limit_test_utils; - -namespace time_limit_consistency { - -using ConsistencyGoldenLoaderTest = testing::Test; - -base::FilePath GetTestGoldensPath() { - base::FilePath path; - base::PathService::Get(base::DIR_SOURCE_ROOT, &path); - - return path.Append( - FILE_PATH_LITERAL("chrome/browser/chromeos/child_accounts/" - "time_limit_consistency_test/test_goldens")); -} - -// Expected outcome is to ignore the test_golden_unsupported suite and return -// only the case within test_golden. -TEST_F(ConsistencyGoldenLoaderTest, LoadTestGoldenCases) { - std::vector<GoldenParam> goldens_list = - LoadGoldenCasesFromPath(GetTestGoldensPath()); - - ConsistencyGoldenCase golden_case; - golden_case.mutable_current_state()->set_time_millis(42); - - ASSERT_EQ(goldens_list.size(), 1ul); - EXPECT_EQ(goldens_list[0].suite_name, "test_golden"); - EXPECT_EQ(goldens_list[0].index, 0); - EXPECT_THAT(goldens_list[0].golden_case, EqualsProto(golden_case)); -} - -} // namespace time_limit_consistency -} // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto deleted file mode 100644 index c3cec2e..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto +++ /dev/null
@@ -1,108 +0,0 @@ -syntax = "proto2"; - -// Used to generate the ChromeOS C++ namespace -package chromeos.time_limit_consistency; - -// Used to generate the Java package -option java_package = "com.google.kids.timelimit.consistency"; -option java_multiple_files = true; - -// The platforms where the test suite may be supported. -enum SupportedPlatform { - UNSPECIFIED_PLATFORM = 0; - ANDROID = 1; - CHROME_OS = 2; -} - -// Policies which may be active. -enum ConsistencyGoldenPolicy { - UNSPECIFIED_POLICY = 0; - NO_ACTIVE_POLICY = 1; - OVERRIDE = 2; - FIXED_LIMIT = 3; - USAGE_LIMIT = 4; -} - -// Days of the week. -enum ConsistencyGoldenEffectiveDay { - UNSPECIFIED_EFFECTIVE_DAY = 0; - MONDAY = 1; - TUESDAY = 2; - WEDNESDAY = 3; - THURSDAY = 4; - FRIDAY = 5; - SATURDAY = 6; - SUNDAY = 7; -} - -// The main object, represents one test suite (and one golden file). -message ConsistencyGolden { - // The platforms where the test is supported. Required - repeated SupportedPlatform supported_platforms = 1; - - // A list of test cases. Required - repeated ConsistencyGoldenCase cases = 2; -} - -// Message representing one test case -message ConsistencyGoldenCase { - // Input policy data. Required - optional ConsistencyGoldenInput input = 1; - - // Simulates the current state when executing. Required - optional ConsistencyGoldenCurrentState current_state = 2; - - // The test's output, used for both the expected and the actual results. - // Required - optional ConsistencyGoldenOutput output = 3; -} - -// The policies configured by the parent. -message ConsistencyGoldenInput { - // List of bedtime configurations for different days of the week. - repeated ConsistencyGoldenWindowLimitEntry window_limits = 1; -} - -// Bedtime configuration for a given day. -message ConsistencyGoldenWindowLimitEntry { - // Which day of the week this configuration relates to. Required - optional ConsistencyGoldenEffectiveDay effective_day = 1; - - // At which hour and minute this bedtime should start. Required - optional ConsistencyGoldenTimeOfDay starts_at = 2; - - // At which hour and minute this bedtime should end. Required - optional ConsistencyGoldenTimeOfDay ends_at = 3; -} - -// Represents a moment of a day. -message ConsistencyGoldenTimeOfDay { - // A given hour. [0-23]. Required - optional int32 hour = 1; - - // A given minute. [0-59]. Required - optional int32 minute = 2; -} - -// Information to represent the current state when executing. -message ConsistencyGoldenCurrentState { - // A timestamp for the desired current time. Required - optional int64 time_millis = 1; - - // String representing the desired timezone, formatted like "GMT+2"/"GMT-3" - // or "America/Sao_Paulo". Required - optional string timezone = 2; -} - -// Information on the output. -message ConsistencyGoldenOutput { - // Whether the device is locked. Required - optional bool is_locked = 1; - - // What is the policy currently taking place. Required - optional ConsistencyGoldenPolicy active_policy = 2; - - // Timestamp of when is the device supposed to unlock. - // This field must be present if and only if the device is locked. - optional int64 next_unlocking_time_millis = 3; -}
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h deleted file mode 100644 index 8bea859..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2019 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. -// -// A gMock matcher for comparing protos and producing a human-readable -// message if the assertion fails. - -#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_ -#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_ - -#include <string> - -#include "testing/gmock/include/gmock/gmock.h" -#include "third_party/protobuf/src/google/protobuf/text_format.h" - -namespace chromeos { -namespace time_limit_consistency { - -MATCHER_P(EqualsProto, message, "equals golden proto") { - std::string expected_serialized, actual_serialized; - message.SerializeToString(&expected_serialized); - arg.SerializeToString(&actual_serialized); - - if (expected_serialized == actual_serialized) { - return true; - } - - std::string expected_readable, actual_readable; - google::protobuf::TextFormat::PrintToString(message, &expected_readable); - google::protobuf::TextFormat::PrintToString(arg, &actual_readable); - - *result_listener << "\n\noutput parses to: \n----------\n" - << actual_readable - << "---------\n\n and should be: \n----------\n" - << expected_readable << "----------"; - - return expected_serialized == actual_serialized; -} - -} // namespace time_limit_consistency -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto deleted file mode 100644 index aefe7d7..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto +++ /dev/null
@@ -1,6 +0,0 @@ -supported_platforms: CHROME_OS -cases { - current_state { - time_millis: 42 - } -}
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto deleted file mode 100644 index 86c65f4..0000000 --- a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto +++ /dev/null
@@ -1,6 +0,0 @@ -supported_platforms: ANDROID -cases { - current_state { - time_millis: 43 - } -}
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc index 8879749..bbf008e 100644 --- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc +++ b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/extensions/api/messaging/native_message_port.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" #include "extensions/browser/api/messaging/message_service.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/browser/extension_registry.h" @@ -344,7 +345,7 @@ message_service->GetChannelDelegate(), port_id, std::move(native_message_host)); message_service->OpenChannelToExtension( - -1 /* source_process_id */, -1 /* source_routing_id */, port_id, + extensions::ChannelEndpoint(profile), port_id, extensions::MessagingEndpoint::ForNativeApp(kDiagnosticsdUiMessageHost), std::move(native_message_port), extension_id, GURL(), std::string() /* channel_name */);
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc index 91d0d16..1e0a48d 100644 --- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc +++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -1038,13 +1038,12 @@ CheckKeyTestCase(rewriter_, test); } -TEST_F(EventRewriterTest, TestRewriteModifiersRemapMany) { +TEST_F(EventRewriterTest, TestRewriteModifiersRemapEscapeToAlt) { // Remap Escape to Alt. chromeos::Preferences::RegisterProfilePrefs(prefs()->registry()); IntegerPrefMember escape; InitModifierKeyPref(&escape, prefs::kLanguageRemapEscapeKeyTo, ui::chromeos::ModifierKey::kAltKey); - rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard"); KeyTestCase e2a_tests[] = { @@ -1061,13 +1060,17 @@ for (const auto& test : e2a_tests) CheckKeyTestCase(rewriter_, test); +} +TEST_F(EventRewriterTest, TestRewriteModifiersRemapAltToControl) { // Remap Alt to Control. + chromeos::Preferences::RegisterProfilePrefs(prefs()->registry()); IntegerPrefMember alt; InitModifierKeyPref(&alt, prefs::kLanguageRemapAltKeyTo, ui::chromeos::ModifierKey::kControlKey); + rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard"); - KeyTestCase a2c_tests[] = { + std::vector<KeyTestCase> a2c_tests = { // Press left Alt. Confirm the event is now VKEY_CONTROL. {ui::ET_KEY_PRESSED, {ui::VKEY_MENU, ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN, ui::DomKey::ALT}, @@ -1091,13 +1094,29 @@ for (const auto& test : a2c_tests) CheckKeyTestCase(rewriter_, test); +} + +TEST_F(EventRewriterTest, TestRewriteModifiersRemapUnderEscapeControlAlt) { + chromeos::Preferences::RegisterProfilePrefs(prefs()->registry()); + + // Remap Escape to Alt. + IntegerPrefMember escape; + InitModifierKeyPref(&escape, prefs::kLanguageRemapEscapeKeyTo, + ui::chromeos::ModifierKey::kAltKey); + + // Remap Alt to Control. + IntegerPrefMember alt; + InitModifierKeyPref(&alt, prefs::kLanguageRemapAltKeyTo, + ui::chromeos::ModifierKey::kControlKey); // Remap Control to Search. IntegerPrefMember control; InitModifierKeyPref(&control, prefs::kLanguageRemapControlKeyTo, ui::chromeos::ModifierKey::kSearchKey); - KeyTestCase c2s_tests[] = { + rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard"); + + std::vector<KeyTestCase> c2s_tests = { // Press left Control. Confirm the event is now VKEY_LWIN. {ui::ET_KEY_PRESSED, {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::EF_CONTROL_DOWN, @@ -1136,15 +1155,46 @@ for (const auto& test : c2s_tests) CheckKeyTestCase(rewriter_, test); +} + +TEST_F(EventRewriterTest, + TestRewriteModifiersRemapUnderEscapeControlAltSearch) { + chromeos::Preferences::RegisterProfilePrefs(prefs()->registry()); + + // Remap Escape to Alt. + IntegerPrefMember escape; + InitModifierKeyPref(&escape, prefs::kLanguageRemapEscapeKeyTo, + ui::chromeos::ModifierKey::kAltKey); + + // Remap Alt to Control. + IntegerPrefMember alt; + InitModifierKeyPref(&alt, prefs::kLanguageRemapAltKeyTo, + ui::chromeos::ModifierKey::kControlKey); + + // Remap Control to Search. + IntegerPrefMember control; + InitModifierKeyPref(&control, prefs::kLanguageRemapControlKeyTo, + ui::chromeos::ModifierKey::kSearchKey); // Remap Search to Backspace. IntegerPrefMember search; InitModifierKeyPref(&search, prefs::kLanguageRemapSearchKeyTo, ui::chromeos::ModifierKey::kBackspaceKey); - KeyTestCase s2b_tests[] = { + rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard"); + + std::vector<KeyTestCase> s2b_tests = { // Release Control and Escape, as Search and Alt would transform Backspace // to Delete. + {ui::ET_KEY_PRESSED, + {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::EF_NONE, + ui::DomKey::CONTROL}, + {ui::VKEY_LWIN, ui::DomCode::META_LEFT, ui::EF_COMMAND_DOWN, + ui::DomKey::META}}, + {ui::ET_KEY_PRESSED, + {ui::VKEY_ESCAPE, ui::DomCode::ESCAPE, ui::EF_NONE, ui::DomKey::ESCAPE}, + {ui::VKEY_MENU, ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN, + ui::DomKey::ALT}}, {ui::ET_KEY_RELEASED, {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::EF_NONE, ui::DomKey::CONTROL}, @@ -1163,13 +1213,18 @@ for (const auto& test : s2b_tests) CheckKeyTestCase(rewriter_, test); +} +TEST_F(EventRewriterTest, TestRewriteModifiersRemapBackspaceToEscape) { // Remap Backspace to Escape. + chromeos::Preferences::RegisterProfilePrefs(prefs()->registry()); IntegerPrefMember backspace; InitModifierKeyPref(&backspace, prefs::kLanguageRemapBackspaceKeyTo, ui::chromeos::ModifierKey::kEscapeKey); - KeyTestCase b2e_tests[] = { + rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard"); + + std::vector<KeyTestCase> b2e_tests = { // Press Backspace. Confirm the event is now VKEY_ESCAPE. {ui::ET_KEY_PRESSED, {ui::VKEY_BACK, ui::DomCode::BACKSPACE, ui::EF_NONE, @@ -2156,8 +2211,15 @@ ui::KeyboardCode key_code, ui::DomCode code, ui::DomKey key) { - ui::KeyEvent press(type, key_code, code, ui::EF_NONE, key, - ui::EventTimeForNow()); + SendKeyEvent(type, key_code, code, key, ui::EF_NONE); + } + + void SendKeyEvent(ui::EventType type, + ui::KeyboardCode key_code, + ui::DomCode code, + ui::DomKey key, + int flags) { + ui::KeyEvent press(type, key_code, code, flags, key, ui::EventTimeForNow()); ui::EventDispatchDetails details = Send(&press); CHECK(!details.dispatcher_destroyed); } @@ -2533,6 +2595,55 @@ EXPECT_TRUE(events[0]->flags() & ui::EF_ALT_DOWN); } +// Tests edge cases of key event rewriting (see https://crbug.com/913209). +TEST_F(EventRewriterAshTest, KeyEventRewritingEdgeCases) { + std::vector<std::unique_ptr<ui::Event>> events; + + // Edge case 1: Press the Launcher button first. Then press the Up Arrow + // button. + SendKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_COMMAND, ui::DomCode::META_LEFT, + ui::DomKey::META); + SendKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::DomCode::ARROW_UP, + ui::DomKey::ARROW_UP, ui::EF_COMMAND_DOWN); + + PopEvents(&events); + EXPECT_EQ(2u, events.size()); + events.clear(); + + SendKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_COMMAND, ui::DomCode::META_LEFT, + ui::DomKey::META); + PopEvents(&events); + + // When releasing the Launcher button, the rewritten event should be released + // as well. + EXPECT_EQ(2u, events.size()); + EXPECT_EQ(ui::VKEY_COMMAND, + static_cast<ui::KeyEvent*>(events[0].get())->key_code()); + EXPECT_EQ(ui::VKEY_PRIOR, + static_cast<ui::KeyEvent*>(events[1].get())->key_code()); + + events.clear(); + + // Edge case 2: Press the Up Arrow button first. Then press the Launch button. + SendKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::DomCode::ARROW_UP, + ui::DomKey::ARROW_UP); + SendKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_COMMAND, ui::DomCode::META_LEFT, + ui::DomKey::META); + + PopEvents(&events); + EXPECT_EQ(2u, events.size()); + events.clear(); + + SendKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_UP, ui::DomCode::ARROW_UP, + ui::DomKey::ARROW_UP, ui::EF_COMMAND_DOWN); + PopEvents(&events); + + // When releasing the Up Arrow button, the rewritten event should be blocked. + EXPECT_EQ(1u, events.size()); + EXPECT_EQ(ui::VKEY_UP, + static_cast<ui::KeyEvent*>(events[0].get())->key_code()); +} + class StickyKeysOverlayTest : public EventRewriterAshTest { public: StickyKeysOverlayTest() : overlay_(NULL) {}
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc index 80a6f29a..cc6d6c26 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -584,7 +584,7 @@ void EventRouter::AddFileWatch(const base::FilePath& local_path, const base::FilePath& virtual_path, const std::string& extension_id, - const BoolCallback& callback) { + BoolCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback.is_null()); @@ -604,7 +604,7 @@ if (is_on_drive) { // For Drive, file watching is done via OnDirectoryChanged(). base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, true)); + FROM_HERE, base::BindOnce(std::move(callback), true)); } else { // For local files, start watching using FileWatcher. watcher->WatchLocalFile( @@ -612,14 +612,14 @@ base::Bind(&EventRouter::HandleFileWatchNotification, weak_factory_.GetWeakPtr(), static_cast<drive::FileChange*>(nullptr)), - callback); + std::move(callback)); } file_watchers_[watch_path] = std::move(watcher); } else { iter->second->AddExtension(extension_id); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, true)); + FROM_HERE, base::BindOnce(std::move(callback), true)); } }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h index 4f6269e..71b8dc3 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.h +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -75,7 +75,7 @@ // KeyedService overrides. void Shutdown() override; - typedef base::Callback<void(bool success)> BoolCallback; + using BoolCallback = base::OnceCallback<void(bool success)>; // Adds a file watch at |local_path|, associated with |virtual_path|, for // an extension with |extension_id|. @@ -88,7 +88,7 @@ void AddFileWatch(const base::FilePath& local_path, const base::FilePath& virtual_path, const std::string& extension_id, - const BoolCallback& callback); + BoolCallback callback); // Removes a file watch at |local_path| for an extension with |extension_id|. //
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc index 35b5ce7..d75f086 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.cc
@@ -27,35 +27,38 @@ void FileStreamMd5Digester::GetMd5Digest( std::unique_ptr<storage::FileStreamReader> stream_reader, - const ResultCallback& callback) { + ResultCallback callback) { + // Only one digest can be running at a time. + DCHECK(callback_.is_null()); + + callback_ = std::move(callback); reader_ = std::move(stream_reader); base::MD5Init(&md5_context_); // Start the read/hash. - ReadNextChunk(callback); + ReadNextChunk(); } -void FileStreamMd5Digester::ReadNextChunk(const ResultCallback& callback) { +void FileStreamMd5Digester::ReadNextChunk() { const int result = reader_->Read(buffer_.get(), kMd5DigestBufferSize, base::BindOnce(&FileStreamMd5Digester::OnChunkRead, - base::Unretained(this), callback)); + base::Unretained(this))); if (result != net::ERR_IO_PENDING) - OnChunkRead(callback, result); + OnChunkRead(result); } -void FileStreamMd5Digester::OnChunkRead(const ResultCallback& callback, - int bytes_read) { +void FileStreamMd5Digester::OnChunkRead(int bytes_read) { if (bytes_read < 0) { // Error - just return empty string. - callback.Run(""); + std::move(callback_).Run(""); return; } else if (bytes_read == 0) { // EOF. base::MD5Digest digest; base::MD5Final(&digest, &md5_context_); std::string result = base::MD5DigestToBase16(digest); - callback.Run(result); + std::move(callback_).Run(result); return; } @@ -64,7 +67,7 @@ base::StringPiece(buffer_->data(), bytes_read)); // Kick off the next read. - ReadNextChunk(callback); + ReadNextChunk(); } } // namespace util
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h index 658c107..e0d080a3d 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h +++ b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/macros.h" #include "base/md5.h" #include "base/memory/ref_counted.h" @@ -24,7 +24,7 @@ // stream. class FileStreamMd5Digester { public: - typedef base::Callback<void(const std::string&)> ResultCallback; + using ResultCallback = base::OnceCallback<void(const std::string&)>; FileStreamMd5Digester(); ~FileStreamMd5Digester(); @@ -35,18 +35,19 @@ // Only one stream can be processed at a time by each digester. Do not call // GetMd5Digest before the results of a previous call have been returned. void GetMd5Digest(std::unique_ptr<storage::FileStreamReader> stream_reader, - const ResultCallback& callback); + ResultCallback callback); private: // Kicks off a read of the next chunk from the stream. - void ReadNextChunk(const ResultCallback& callback); + void ReadNextChunk(); // Handles the incoming chunk of data from a stream read. - void OnChunkRead(const ResultCallback& callback, int bytes_read); + void OnChunkRead(int bytes_read); // Maximum chunk size for read operations. std::unique_ptr<storage::FileStreamReader> reader_; scoped_refptr<net::IOBuffer> buffer_; base::MD5Context md5_context_; + ResultCallback callback_; DISALLOW_COPY_AND_ASSIGN(FileStreamMd5Digester); };
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index 126a291..b9009e14 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -252,11 +252,11 @@ // Calls a response callback (on the UI thread) with a file content hash // computed on the IO thread. void ComputeChecksumRespondOnUIThread( - const base::Callback<void(const std::string&)>& callback, + base::OnceCallback<void(const std::string&)> callback, const std::string& hash) { DCHECK_CURRENTLY_ON(BrowserThread::IO); base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(callback, hash)); + base::BindOnce(std::move(callback), hash)); } // Calls a response callback on the UI thread. @@ -445,7 +445,7 @@ // Obsolete. Fallback code if storage::WatcherManager is not implemented. event_router->AddFileWatch( file_system_url.path(), file_system_url.virtual_path(), extension_id(), - base::Bind(&FileWatchFunctionBase::RespondWith, this)); + base::BindOnce(&FileWatchFunctionBase::RespondWith, this)); } void FileManagerPrivateInternalRemoveFileWatchFunction:: @@ -961,16 +961,16 @@ file_system_context->CreateFileStreamReader( file_system_url, 0, storage::kMaximumLength, base::Time()); - FileStreamMd5Digester::ResultCallback result_callback = base::Bind( + FileStreamMd5Digester::ResultCallback result_callback = base::BindOnce( &ComputeChecksumRespondOnUIThread, - base::Bind( + base::BindOnce( &FileManagerPrivateInternalComputeChecksumFunction::RespondWith, this)); base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&FileStreamMd5Digester::GetMd5Digest, - base::Unretained(digester_.get()), base::Passed(&reader), - result_callback)); + base::Unretained(digester_.get()), std::move(reader), + std::move(result_callback))); return RespondLater(); }
diff --git a/chrome/browser/chromeos/extensions/incoming_native_messaging_apitest.cc b/chrome/browser/chromeos/extensions/incoming_native_messaging_apitest.cc index 1cd6b88..29d6a74 100644 --- a/chrome/browser/chromeos/extensions/incoming_native_messaging_apitest.cc +++ b/chrome/browser/chromeos/extensions/incoming_native_messaging_apitest.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "content/public/common/child_process_host.h" #include "content/public/test/browser_test.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" #include "extensions/browser/api/messaging/message_service.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/common/api/messaging/messaging_endpoint.h" @@ -88,8 +89,7 @@ message_service->GetChannelDelegate(), port_id, std::move(native_message_host)); message_service->OpenChannelToExtension( - content::ChildProcessHost::kInvalidUniqueID /* source_process_id */, - MSG_ROUTING_NONE /* source_routing_id */, port_id, + extensions::ChannelEndpoint(profile()), port_id, extensions::MessagingEndpoint::ForNativeApp(kFakeNativeAppName), std::move(native_message_port), extension_->id(), GURL(), std::string() /* channel_name */);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 2edcaf5..ce6ff531 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -931,7 +931,8 @@ TestCase("myFilesFolderRename"), TestCase("myFilesFolderRename").EnableMyFilesVolume(), TestCase("myFilesUpdatesChildren"), - TestCase("myFilesUpdatesChildren").EnableMyFilesVolume())); + TestCase("myFilesUpdatesChildren").EnableMyFilesVolume(), + TestCase("myFilesAutoExpandOnce").EnableMyFilesVolume())); WRAPPED_INSTANTIATE_TEST_SUITE_P( InstallLinuxPackageDialog, /* install_linux_package_dialog.js */ @@ -952,6 +953,8 @@ TestCase("recentsDownloads"), TestCase("recentsDrive").DisableDriveFs(), TestCase("recentsDrive").EnableDriveFs(), + TestCase("recentsCrostiniNotMounted"), + TestCase("recentsCrostiniMounted"), TestCase("recentsDownloadsAndDrive").DisableDriveFs(), TestCase("recentsDownloadsAndDrive").EnableDriveFs(), TestCase("recentsDownloadsAndDriveWithOverlap").DisableDriveFs(),
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc index f8a2884..67b5f5d3 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -250,6 +250,12 @@ chromeos::PowerManagerClient::Get(), disk_mount_manager_.get()); } + void TearDown() override { + main_profile_.reset(); + disk_mount_manager_.reset(); + chromeos::PowerManagerClient::Shutdown(); + } + Profile* profile() const { return main_profile_->profile(); } VolumeManager* volume_manager() const { return main_profile_->volume_manager();
diff --git a/chrome/browser/chromeos/fileapi/recent_download_source.cc b/chrome/browser/chromeos/fileapi/recent_disk_source.cc similarity index 70% rename from chrome/browser/chromeos/fileapi/recent_download_source.cc rename to chrome/browser/chromeos/fileapi/recent_disk_source.cc index 223f745..c82752a 100644 --- a/chrome/browser/chromeos/fileapi/recent_download_source.cc +++ b/chrome/browser/chromeos/fileapi/recent_disk_source.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/fileapi/recent_download_source.h" +#include "chrome/browser/chromeos/fileapi/recent_disk_source.h" #include <utility> #include "base/bind.h" #include "base/files/file_path.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" +#include "base/strings/string_util.h" #include "base/task/post_task.h" #include "base/time/time.h" -#include "chrome/browser/chromeos/file_manager/path_util.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "storage/browser/fileapi/external_mount_points.h" @@ -72,21 +72,23 @@ } // namespace -const char RecentDownloadSource::kLoadHistogramName[] = - "FileBrowser.Recent.LoadDownloads"; - -RecentDownloadSource::RecentDownloadSource(Profile* profile) - : mount_point_name_( - file_manager::util::GetDownloadsMountPointName(profile)), +RecentDiskSource::RecentDiskSource(std::string mount_point_name, + bool ignore_dotfiles, + int max_depth, + std::string uma_histogram_name) + : mount_point_name_(std::move(mount_point_name)), + ignore_dotfiles_(ignore_dotfiles), + max_depth_(max_depth), + uma_histogram_name_(std::move(uma_histogram_name)), weak_ptr_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); } -RecentDownloadSource::~RecentDownloadSource() { +RecentDiskSource::~RecentDiskSource() { DCHECK_CURRENTLY_ON(BrowserThread::UI); } -void RecentDownloadSource::GetRecentFiles(Params params) { +void RecentDiskSource::GetRecentFiles(Params params) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!params_.has_value()); DCHECK(build_start_time_.is_null()); @@ -94,20 +96,29 @@ DCHECK_EQ(0, inflight_stats_); DCHECK(recent_files_.empty()); + // Return immediately if mount point does not exist. + storage::ExternalMountPoints* mount_points = + storage::ExternalMountPoints::GetSystemInstance(); + base::FilePath path; + if (!mount_points->GetRegisteredPath(mount_point_name_, &path)) { + std::move(params.callback()).Run({}); + return; + } + params_.emplace(std::move(params)); DCHECK(params_.has_value()); build_start_time_ = base::TimeTicks::Now(); - ScanDirectory(base::FilePath()); + ScanDirectory(base::FilePath(), 1); } -void RecentDownloadSource::ScanDirectory(const base::FilePath& path) { +void RecentDiskSource::ScanDirectory(const base::FilePath& path, int depth) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(params_.has_value()); - storage::FileSystemURL url = BuildDownloadsURL(path); + storage::FileSystemURL url = BuildDiskURL(path); ++inflight_readdirs_; base::PostTaskWithTraits( @@ -115,12 +126,13 @@ base::BindOnce( &ReadDirectoryOnIOThread, base::WrapRefCounted(params_.value().file_system_context()), url, - base::Bind(&RecentDownloadSource::OnReadDirectory, - weak_ptr_factory_.GetWeakPtr(), path))); + base::BindRepeating(&RecentDiskSource::OnReadDirectory, + weak_ptr_factory_.GetWeakPtr(), path, depth))); } -void RecentDownloadSource::OnReadDirectory( +void RecentDiskSource::OnReadDirectory( const base::FilePath& path, + const int depth, base::File::Error result, storage::FileSystemOperation::FileEntryList entries, bool has_more) { @@ -128,11 +140,21 @@ DCHECK(params_.has_value()); for (const auto& entry : entries) { + // Ignore directories and files that start with dot. + if (ignore_dotfiles_ && + base::StartsWith(entry.name.value(), ".", + base::CompareCase::INSENSITIVE_ASCII)) { + continue; + } base::FilePath subpath = path.Append(entry.name); + if (entry.type == filesystem::mojom::FsFileType::DIRECTORY) { - ScanDirectory(subpath); + if (max_depth_ > 0 && depth >= max_depth_) { + continue; + } + ScanDirectory(subpath, depth + 1); } else { - storage::FileSystemURL url = BuildDownloadsURL(subpath); + storage::FileSystemURL url = BuildDiskURL(subpath); ++inflight_stats_; base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, @@ -140,7 +162,7 @@ &GetMetadataOnIOThread, base::WrapRefCounted(params_.value().file_system_context()), url, storage::FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED, - base::BindOnce(&RecentDownloadSource::OnGetMetadata, + base::BindOnce(&RecentDiskSource::OnGetMetadata, weak_ptr_factory_.GetWeakPtr(), url))); } } @@ -152,9 +174,9 @@ OnReadOrStatFinished(); } -void RecentDownloadSource::OnGetMetadata(const storage::FileSystemURL& url, - base::File::Error result, - const base::File::Info& info) { +void RecentDiskSource::OnGetMetadata(const storage::FileSystemURL& url, + base::File::Error result, + const base::File::Info& info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(params_.has_value()); @@ -169,7 +191,7 @@ OnReadOrStatFinished(); } -void RecentDownloadSource::OnReadOrStatFinished() { +void RecentDiskSource::OnReadOrStatFinished() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (inflight_readdirs_ > 0 || inflight_stats_ > 0) @@ -183,8 +205,8 @@ } DCHECK(!build_start_time_.is_null()); - UMA_HISTOGRAM_TIMES(kLoadHistogramName, - base::TimeTicks::Now() - build_start_time_); + UmaHistogramTimes(uma_histogram_name_, + base::TimeTicks::Now() - build_start_time_); build_start_time_ = base::TimeTicks(); Params params = std::move(params_.value()); @@ -199,14 +221,13 @@ std::move(params.callback()).Run(std::move(files)); } -storage::FileSystemURL RecentDownloadSource::BuildDownloadsURL( +storage::FileSystemURL RecentDiskSource::BuildDiskURL( const base::FilePath& path) const { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(params_.has_value()); storage::ExternalMountPoints* mount_points = storage::ExternalMountPoints::GetSystemInstance(); - return mount_points->CreateExternalFileSystemURL(params_.value().origin(), mount_point_name_, path); }
diff --git a/chrome/browser/chromeos/fileapi/recent_disk_source.h b/chrome/browser/chromeos/fileapi/recent_disk_source.h new file mode 100644 index 0000000..13fc983 --- /dev/null +++ b/chrome/browser/chromeos/fileapi/recent_disk_source.h
@@ -0,0 +1,89 @@ +// Copyright 2017 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_CHROMEOS_FILEAPI_RECENT_DISK_SOURCE_H_ +#define CHROME_BROWSER_CHROMEOS_FILEAPI_RECENT_DISK_SOURCE_H_ + +#include <memory> +#include <queue> +#include <string> +#include <vector> + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/fileapi/recent_file.h" +#include "chrome/browser/chromeos/fileapi/recent_model.h" +#include "chrome/browser/chromeos/fileapi/recent_source.h" +#include "storage/browser/fileapi/file_system_operation.h" + +namespace chromeos { + +// RecentSource implementation for local disks. +// Used for Downloads and fuse-based Crostini. +// +// All member functions must be called on the UI thread. +class RecentDiskSource : public RecentSource { + public: + // Create a RecentDiskSource for the volume registered to |mount_point_name|. + // Does nothing if no volume is registered at |mount_point_name|. + // If |ignore_dotfiles| is true, recents will ignore directories and files + // starting with a dot. Set |max_depth| to zero for unlimited depth. + RecentDiskSource(std::string mount_point_name, + bool ignore_dotfiles, + int max_depth, + std::string uma_histogram_name); + ~RecentDiskSource() override; + + // RecentSource overrides: + void GetRecentFiles(Params params) override; + + private: + FRIEND_TEST_ALL_PREFIXES(RecentDiskSourceTest, GetRecentFiles_UmaStats); + + static const char kLoadHistogramName[]; + + void ScanDirectory(const base::FilePath& path, int depth); + void OnReadDirectory(const base::FilePath& path, + int depth, + base::File::Error result, + storage::FileSystemOperation::FileEntryList entries, + bool has_more); + void OnGetMetadata(const storage::FileSystemURL& url, + base::File::Error result, + const base::File::Info& info); + void OnReadOrStatFinished(); + + storage::FileSystemURL BuildDiskURL(const base::FilePath& path) const; + + const std::string mount_point_name_; + const bool ignore_dotfiles_; + const int max_depth_; + const std::string uma_histogram_name_; + + // Parameters given to GetRecentFiles(). + base::Optional<Params> params_; + + // Time when the build started. + base::TimeTicks build_start_time_; + // Number of ReadDirectory() calls in flight. + int inflight_readdirs_ = 0; + // Number of GetMetadata() calls in flight. + int inflight_stats_ = 0; + // Most recently modified files. + std::priority_queue<RecentFile, std::vector<RecentFile>, RecentFileComparator> + recent_files_; + + base::WeakPtrFactory<RecentDiskSource> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(RecentDiskSource); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_FILEAPI_RECENT_DISK_SOURCE_H_
diff --git a/chrome/browser/chromeos/fileapi/recent_disk_source_unittest.cc b/chrome/browser/chromeos/fileapi/recent_disk_source_unittest.cc new file mode 100644 index 0000000..692a589 --- /dev/null +++ b/chrome/browser/chromeos/fileapi/recent_disk_source_unittest.cc
@@ -0,0 +1,223 @@ +// Copyright 2017 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 <algorithm> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/chromeos/fileapi/recent_disk_source.h" +#include "chrome/browser/chromeos/fileapi/recent_file.h" +#include "chrome/browser/chromeos/fileapi/recent_source.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "storage/browser/fileapi/external_mount_points.h" +#include "storage/browser/fileapi/file_system_context.h" +#include "storage/browser/fileapi/file_system_url.h" +#include "storage/browser/test/test_file_system_context.h" +#include "storage/common/fileapi/file_system_mount_option.h" +#include "storage/common/fileapi/file_system_types.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace chromeos { + +class RecentDiskSourceTest : public testing::Test { + public: + RecentDiskSourceTest() : origin_("https://example.com/") {} + + void SetUp() override { + profile_ = std::make_unique<TestingProfile>(); + + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + + file_system_context_ = content::CreateFileSystemContextForTesting( + nullptr, temp_dir_.GetPath()); + + mount_point_name_ = + file_manager::util::GetDownloadsMountPointName(profile_.get()); + storage::ExternalMountPoints* mount_points = + storage::ExternalMountPoints::GetSystemInstance(); + + mount_points->RevokeFileSystem(mount_point_name_); + ASSERT_TRUE(mount_points->RegisterFileSystem( + mount_point_name_, storage::kFileSystemTypeTest, + storage::FileSystemMountOption(), base::FilePath())); + + source_ = std::make_unique<RecentDiskSource>( + mount_point_name_, false /* ignore_dotfiles */, 0 /* max_depth */, + uma_histogram_name_); + } + + protected: + bool CreateEmptyFile(const std::string& filename, const base::Time& time) { + base::File file(temp_dir_.GetPath().Append(filename), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + if (!file.IsValid()) + return false; + + return file.SetTimes(time, time); + } + + std::vector<RecentFile> GetRecentFiles(size_t max_files, + const base::Time& cutoff_time) { + std::vector<RecentFile> files; + + base::RunLoop run_loop; + + source_->GetRecentFiles(RecentSource::Params( + file_system_context_.get(), origin_, max_files, cutoff_time, + base::BindOnce( + [](base::RunLoop* run_loop, std::vector<RecentFile>* out_files, + std::vector<RecentFile> files) { + run_loop->Quit(); + *out_files = std::move(files); + }, + &run_loop, &files))); + + run_loop.Run(); + + return files; + } + + content::TestBrowserThreadBundle thread_bundle_; + const GURL origin_; + std::unique_ptr<TestingProfile> profile_; + base::ScopedTempDir temp_dir_; + scoped_refptr<storage::FileSystemContext> file_system_context_; + std::string mount_point_name_; + const std::string uma_histogram_name_ = "uma_histogram_name"; + std::unique_ptr<RecentDiskSource> source_; + base::Time base_time_; +}; + +TEST_F(RecentDiskSourceTest, GetRecentFiles) { + // Oldest + ASSERT_TRUE(CreateEmptyFile("1.jpg", base::Time::FromJavaTime(1000))); + ASSERT_TRUE(CreateEmptyFile("2.jpg", base::Time::FromJavaTime(2000))); + ASSERT_TRUE(CreateEmptyFile("3.jpg", base::Time::FromJavaTime(3000))); + ASSERT_TRUE(CreateEmptyFile("4.jpg", base::Time::FromJavaTime(4000))); + // Newest + + std::vector<RecentFile> files = GetRecentFiles(3, base::Time()); + + std::sort(files.begin(), files.end(), RecentFileComparator()); + + ASSERT_EQ(3u, files.size()); + EXPECT_EQ("4.jpg", files[0].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified()); + EXPECT_EQ("3.jpg", files[1].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified()); + EXPECT_EQ("2.jpg", files[2].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(2000), files[2].last_modified()); +} + +TEST_F(RecentDiskSourceTest, GetRecentFiles_CutoffTime) { + // Oldest + ASSERT_TRUE(CreateEmptyFile("1.jpg", base::Time::FromJavaTime(1000))); + ASSERT_TRUE(CreateEmptyFile("2.jpg", base::Time::FromJavaTime(2000))); + ASSERT_TRUE(CreateEmptyFile("3.jpg", base::Time::FromJavaTime(3000))); + ASSERT_TRUE(CreateEmptyFile("4.jpg", base::Time::FromJavaTime(4000))); + // Newest + + std::vector<RecentFile> files = + GetRecentFiles(3, base::Time::FromJavaTime(2500)); + + std::sort(files.begin(), files.end(), RecentFileComparator()); + + ASSERT_EQ(2u, files.size()); + EXPECT_EQ("4.jpg", files[0].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified()); + EXPECT_EQ("3.jpg", files[1].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified()); +} + +TEST_F(RecentDiskSourceTest, IgnoreDotFiles) { + ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append(".ignore"))); + ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("noignore"))); + + // Oldest + ASSERT_TRUE( + CreateEmptyFile("noignore/1.jpg", base::Time::FromJavaTime(1000))); + ASSERT_TRUE(CreateEmptyFile(".ignore/2.jpg", base::Time::FromJavaTime(2000))); + ASSERT_TRUE(CreateEmptyFile("3.jpg", base::Time::FromJavaTime(3000))); + ASSERT_TRUE(CreateEmptyFile(".4.jpg", base::Time::FromJavaTime(4000))); + // Newest + + std::vector<RecentFile> files = GetRecentFiles(4, base::Time()); + + std::sort(files.begin(), files.end(), RecentFileComparator()); + + ASSERT_EQ(4u, files.size()); + EXPECT_EQ(".4.jpg", files[0].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified()); + EXPECT_EQ("3.jpg", files[1].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified()); + EXPECT_EQ("2.jpg", files[2].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(2000), files[2].last_modified()); + EXPECT_EQ("1.jpg", files[3].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(1000), files[3].last_modified()); + + source_ = std::make_unique<RecentDiskSource>( + mount_point_name_, true /* ignore_dotfiles */, 0 /* max_depth */, + uma_histogram_name_); + + files = GetRecentFiles(4, base::Time()); + + std::sort(files.begin(), files.end(), RecentFileComparator()); + + ASSERT_EQ(2u, files.size()); + EXPECT_EQ("3.jpg", files[0].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(3000), files[0].last_modified()); + EXPECT_EQ("1.jpg", files[1].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(1000), files[1].last_modified()); +} + +TEST_F(RecentDiskSourceTest, MaxDepth) { + ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("a"))); + ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("a/b"))); + ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("a/b/c"))); + + // Oldest + ASSERT_TRUE(CreateEmptyFile("1.jpg", base::Time::FromJavaTime(1000))); + ASSERT_TRUE(CreateEmptyFile("a/2.jpg", base::Time::FromJavaTime(2000))); + ASSERT_TRUE(CreateEmptyFile("a/b/3.jpg", base::Time::FromJavaTime(3000))); + ASSERT_TRUE(CreateEmptyFile("a/b/c/4.jpg", base::Time::FromJavaTime(4000))); + // Newest + + std::vector<RecentFile> files = GetRecentFiles(4, base::Time()); + ASSERT_EQ(4u, files.size()); + + source_ = std::make_unique<RecentDiskSource>(mount_point_name_, false, 2, + uma_histogram_name_); + + files = GetRecentFiles(4, base::Time()); + + std::sort(files.begin(), files.end(), RecentFileComparator()); + + ASSERT_EQ(2u, files.size()); + EXPECT_EQ("2.jpg", files[0].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(2000), files[0].last_modified()); + EXPECT_EQ("1.jpg", files[1].url().path().BaseName().value()); + EXPECT_EQ(base::Time::FromJavaTime(1000), files[1].last_modified()); +} + +TEST_F(RecentDiskSourceTest, GetRecentFiles_UmaStats) { + base::HistogramTester histogram_tester; + + GetRecentFiles(3, base::Time()); + + histogram_tester.ExpectTotalCount(uma_histogram_name_, 1); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/recent_download_source.h b/chrome/browser/chromeos/fileapi/recent_download_source.h deleted file mode 100644 index 4b96e225..0000000 --- a/chrome/browser/chromeos/fileapi/recent_download_source.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2017 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_CHROMEOS_FILEAPI_RECENT_DOWNLOAD_SOURCE_H_ -#define CHROME_BROWSER_CHROMEOS_FILEAPI_RECENT_DOWNLOAD_SOURCE_H_ - -#include <memory> -#include <queue> -#include <string> -#include <vector> - -#include "base/files/file.h" -#include "base/files/file_path.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/optional.h" -#include "base/time/time.h" -#include "chrome/browser/chromeos/fileapi/recent_file.h" -#include "chrome/browser/chromeos/fileapi/recent_model.h" -#include "chrome/browser/chromeos/fileapi/recent_source.h" -#include "storage/browser/fileapi/file_system_operation.h" - -class Profile; - -namespace chromeos { - -// RecentSource implementation for Downloads files. -// -// All member functions must be called on the UI thread. -class RecentDownloadSource : public RecentSource { - public: - explicit RecentDownloadSource(Profile* profile); - ~RecentDownloadSource() override; - - // RecentSource overrides: - void GetRecentFiles(Params params) override; - - private: - FRIEND_TEST_ALL_PREFIXES(RecentDownloadSourceTest, GetRecentFiles_UmaStats); - - static const char kLoadHistogramName[]; - - void ScanDirectory(const base::FilePath& path); - void OnReadDirectory(const base::FilePath& path, - base::File::Error result, - storage::FileSystemOperation::FileEntryList entries, - bool has_more); - void OnGetMetadata(const storage::FileSystemURL& url, - base::File::Error result, - const base::File::Info& info); - void OnReadOrStatFinished(); - - storage::FileSystemURL BuildDownloadsURL(const base::FilePath& path) const; - - const std::string mount_point_name_; - - // Parameters given to GetRecentFiles(). - base::Optional<Params> params_; - - // Time when the build started. - base::TimeTicks build_start_time_; - // Number of ReadDirectory() calls in flight. - int inflight_readdirs_ = 0; - // Number of GetMetadata() calls in flight. - int inflight_stats_ = 0; - // Most recently modified files. - std::priority_queue<RecentFile, std::vector<RecentFile>, RecentFileComparator> - recent_files_; - - base::WeakPtrFactory<RecentDownloadSource> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(RecentDownloadSource); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_FILEAPI_RECENT_DOWNLOAD_SOURCE_H_
diff --git a/chrome/browser/chromeos/fileapi/recent_download_source_unittest.cc b/chrome/browser/chromeos/fileapi/recent_download_source_unittest.cc deleted file mode 100644 index f697a34c..0000000 --- a/chrome/browser/chromeos/fileapi/recent_download_source_unittest.cc +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright 2017 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 <algorithm> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/files/file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/run_loop.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/time/time.h" -#include "chrome/browser/chromeos/file_manager/path_util.h" -#include "chrome/browser/chromeos/fileapi/recent_download_source.h" -#include "chrome/browser/chromeos/fileapi/recent_file.h" -#include "chrome/browser/chromeos/fileapi/recent_source.h" -#include "chrome/test/base/testing_profile.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "storage/browser/fileapi/external_mount_points.h" -#include "storage/browser/fileapi/file_system_context.h" -#include "storage/browser/fileapi/file_system_url.h" -#include "storage/browser/test/test_file_system_context.h" -#include "storage/common/fileapi/file_system_mount_option.h" -#include "storage/common/fileapi/file_system_types.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace chromeos { - -class RecentDownloadSourceTest : public testing::Test { - public: - RecentDownloadSourceTest() : origin_("https://example.com/") {} - - void SetUp() override { - profile_ = std::make_unique<TestingProfile>(); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - file_system_context_ = content::CreateFileSystemContextForTesting( - nullptr, temp_dir_.GetPath()); - - RegisterFakeDownloadsFileSystem(); - - source_ = std::make_unique<RecentDownloadSource>(profile_.get()); - } - - protected: - void RegisterFakeDownloadsFileSystem() const { - storage::ExternalMountPoints* mount_points = - storage::ExternalMountPoints::GetSystemInstance(); - std::string mount_point_name = - file_manager::util::GetDownloadsMountPointName(profile_.get()); - - mount_points->RevokeFileSystem(mount_point_name); - ASSERT_TRUE(mount_points->RegisterFileSystem( - mount_point_name, storage::kFileSystemTypeTest, - storage::FileSystemMountOption(), base::FilePath())); - } - - bool CreateEmptyFile(const std::string& filename, const base::Time& time) { - base::File file(temp_dir_.GetPath().Append(filename), - base::File::FLAG_CREATE | base::File::FLAG_WRITE); - if (!file.IsValid()) - return false; - - return file.SetTimes(time, time); - } - - std::vector<RecentFile> GetRecentFiles(size_t max_files, - const base::Time& cutoff_time) { - std::vector<RecentFile> files; - - base::RunLoop run_loop; - - source_->GetRecentFiles(RecentSource::Params( - file_system_context_.get(), origin_, max_files, cutoff_time, - base::BindOnce( - [](base::RunLoop* run_loop, std::vector<RecentFile>* out_files, - std::vector<RecentFile> files) { - run_loop->Quit(); - *out_files = std::move(files); - }, - &run_loop, &files))); - - run_loop.Run(); - - return files; - } - - content::TestBrowserThreadBundle thread_bundle_; - const GURL origin_; - std::unique_ptr<TestingProfile> profile_; - base::ScopedTempDir temp_dir_; - scoped_refptr<storage::FileSystemContext> file_system_context_; - std::unique_ptr<RecentDownloadSource> source_; - base::Time base_time_; -}; - -TEST_F(RecentDownloadSourceTest, GetRecentFiles) { - // Oldest - ASSERT_TRUE(CreateEmptyFile("1.jpg", base::Time::FromJavaTime(1000))); - ASSERT_TRUE(CreateEmptyFile("2.jpg", base::Time::FromJavaTime(2000))); - ASSERT_TRUE(CreateEmptyFile("3.jpg", base::Time::FromJavaTime(3000))); - ASSERT_TRUE(CreateEmptyFile("4.jpg", base::Time::FromJavaTime(4000))); - // Newest - - std::vector<RecentFile> files = GetRecentFiles(3, base::Time()); - - std::sort(files.begin(), files.end(), RecentFileComparator()); - - ASSERT_EQ(3u, files.size()); - EXPECT_EQ("4.jpg", files[0].url().path().BaseName().value()); - EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified()); - EXPECT_EQ("3.jpg", files[1].url().path().BaseName().value()); - EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified()); - EXPECT_EQ("2.jpg", files[2].url().path().BaseName().value()); - EXPECT_EQ(base::Time::FromJavaTime(2000), files[2].last_modified()); -} - -TEST_F(RecentDownloadSourceTest, GetRecentFiles_CutoffTime) { - // Oldest - ASSERT_TRUE(CreateEmptyFile("1.jpg", base::Time::FromJavaTime(1000))); - ASSERT_TRUE(CreateEmptyFile("2.jpg", base::Time::FromJavaTime(2000))); - ASSERT_TRUE(CreateEmptyFile("3.jpg", base::Time::FromJavaTime(3000))); - ASSERT_TRUE(CreateEmptyFile("4.jpg", base::Time::FromJavaTime(4000))); - // Newest - - std::vector<RecentFile> files = - GetRecentFiles(3, base::Time::FromJavaTime(2500)); - - std::sort(files.begin(), files.end(), RecentFileComparator()); - - ASSERT_EQ(2u, files.size()); - EXPECT_EQ("4.jpg", files[0].url().path().BaseName().value()); - EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified()); - EXPECT_EQ("3.jpg", files[1].url().path().BaseName().value()); - EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified()); -} - -TEST_F(RecentDownloadSourceTest, GetRecentFiles_UmaStats) { - base::HistogramTester histogram_tester; - - GetRecentFiles(3, base::Time()); - - histogram_tester.ExpectTotalCount(RecentDownloadSource::kLoadHistogramName, - 1); -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/recent_model.cc b/chrome/browser/chromeos/fileapi/recent_model.cc index 7bd00f0a..68e51ff 100644 --- a/chrome/browser/chromeos/fileapi/recent_model.cc +++ b/chrome/browser/chromeos/fileapi/recent_model.cc
@@ -15,8 +15,9 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/fileapi/recent_arc_media_source.h" -#include "chrome/browser/chromeos/fileapi/recent_download_source.h" +#include "chrome/browser/chromeos/fileapi/recent_disk_source.h" #include "chrome/browser/chromeos/fileapi/recent_drive_source.h" #include "chrome/browser/chromeos/fileapi/recent_file.h" #include "chrome/browser/chromeos/fileapi/recent_model_factory.h" @@ -41,7 +42,16 @@ Profile* profile) { std::vector<std::unique_ptr<RecentSource>> sources; sources.emplace_back(std::make_unique<RecentArcMediaSource>(profile)); - sources.emplace_back(std::make_unique<RecentDownloadSource>(profile)); + // Crostini. + sources.emplace_back(std::make_unique<RecentDiskSource>( + file_manager::util::GetCrostiniMountPointName(profile), + true /* ignore_dotfiles */, 4 /* max_depth */, + "FileBrowser.Recent.LoadCrostini")); + // Downloads / MyFiles. + sources.emplace_back(std::make_unique<RecentDiskSource>( + file_manager::util::GetDownloadsMountPointName(profile), + false /* ignore_dotfiles */, 0 /* max_depth unlimited */, + "FileBrowser.Recent.LoadDownloads")); sources.emplace_back(std::make_unique<RecentDriveSource>(profile)); return sources; }
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc index 1c29312..3f1f9e1 100644 --- a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc +++ b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
@@ -234,8 +234,8 @@ ASSERT_TRUE(disabled_listener.WaitUntilSatisfied()); ASSERT_TRUE(disabled_listener.was_satisfied()); - ui::IMEBridge::Get()->SetInputContextHandler(NULL); - ui::IMEBridge::Get()->SetCandidateWindowHandler(NULL); + ui::IMEBridge::Get()->SetInputContextHandler(nullptr); + ui::IMEBridge::Get()->SetCandidateWindowHandler(nullptr); } IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest, @@ -1020,8 +1020,8 @@ EXPECT_EQ("", mock_input_context->last_commit_text()); } - ui::IMEBridge::Get()->SetInputContextHandler(NULL); - ui::IMEBridge::Get()->SetCandidateWindowHandler(NULL); + ui::IMEBridge::Get()->SetInputContextHandler(nullptr); + ui::IMEBridge::Get()->SetCandidateWindowHandler(nullptr); } IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest, RestrictedKeyboard) { @@ -1134,6 +1134,9 @@ ASSERT_TRUE(focus_listener.WaitUntilSatisfied()); ASSERT_TRUE(focus_listener.was_satisfied()); } + + ui::IMEBridge::Get()->SetInputContextHandler(nullptr); + ui::IMEBridge::Get()->SetCandidateWindowHandler(nullptr); } IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest, ShouldDoLearning) { @@ -1163,6 +1166,9 @@ engine_handler->FocusIn(context); ASSERT_TRUE(focus_listener.WaitUntilSatisfied()); ASSERT_TRUE(focus_listener.was_satisfied()); + + ui::IMEBridge::Get()->SetInputContextHandler(nullptr); + ui::IMEBridge::Get()->SetCandidateWindowHandler(nullptr); } } // namespace
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index 476d32d..0963fa9 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -163,11 +163,8 @@ } os << "\n"; os << "extra_input_methods (size=" << extra_input_methods.size() << "):"; - for (std::map<std::string, InputMethodDescriptor>::const_iterator it = - extra_input_methods.begin(); - it != extra_input_methods.end(); - ++it) { - os << " '" << it->first << "' => '" << it->second.id() << "',\n"; + for (const auto& entry : extra_input_methods) { + os << " '" << entry.first << "' => '" << entry.second.id() << "',\n"; } os << "pending_input_method_id: '" << pending_input_method_id << "'\n"; os << "input_view_url: '" << input_view_url << "'\n"; @@ -194,8 +191,7 @@ if (descriptor) { result->push_back(*descriptor); } else { - std::map<std::string, InputMethodDescriptor>::const_iterator ix = - extra_input_methods.find(input_method_id); + const auto ix = extra_input_methods.find(input_method_id); if (ix != extra_input_methods.end()) result->push_back(ix->second); else @@ -226,8 +222,7 @@ const InputMethodDescriptor* ime = manager_->util_.GetInputMethodDescriptorFromId(input_method_id); if (!ime) { - std::map<std::string, InputMethodDescriptor>::const_iterator ix = - extra_input_methods.find(input_method_id); + const auto ix = extra_input_methods.find(input_method_id); if (ix != extra_input_methods.end()) ime = &ix->second; } @@ -626,13 +621,10 @@ // Remove the extra input methods with |extension_id|. std::map<std::string, InputMethodDescriptor> new_extra_input_methods; - for (std::map<std::string, InputMethodDescriptor>::iterator i = - extra_input_methods.begin(); - i != extra_input_methods.end(); - ++i) { + for (const auto& entry : extra_input_methods) { if (extension_id != - extension_ime_util::GetExtensionIDFromInputMethodID(i->first)) - new_extra_input_methods[i->first] = i->second; + extension_ime_util::GetExtensionIDFromInputMethodID(entry.first)) + new_extra_input_methods[entry.first] = entry.second; } extra_input_methods.swap(new_extra_input_methods); @@ -654,12 +646,10 @@ InputMethodDescriptors* result) { // Build the extension input method descriptors from the extra input // methods cache |extra_input_methods|. - std::map<std::string, InputMethodDescriptor>::iterator iter; - for (iter = extra_input_methods.begin(); iter != extra_input_methods.end(); - ++iter) { - if (extension_ime_util::IsExtensionIME(iter->first) || - extension_ime_util::IsArcIME(iter->first)) { - result->push_back(iter->second); + for (const auto& entry : extra_input_methods) { + if (extension_ime_util::IsExtensionIME(entry.first) || + extension_ime_util::IsArcIME(entry.first)) { + result->push_back(entry.second); } } } @@ -672,30 +662,25 @@ bool active_imes_changed = false; bool switch_to_pending = false; - for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter = - extra_input_methods.begin(); - extra_iter != extra_input_methods.end(); - ++extra_iter) { - if (extension_ime_util::IsComponentExtensionIME(extra_iter->first)) + for (const auto& entry : extra_input_methods) { + if (extension_ime_util::IsComponentExtensionIME(entry.first)) continue; // Do not filter component extension. - if (pending_input_method_id == extra_iter->first) + if (pending_input_method_id == entry.first) switch_to_pending = true; - std::vector<std::string>::iterator active_iter = + const auto active_iter = std::find(active_input_method_ids.begin(), - active_input_method_ids.end(), - extra_iter->first); + active_input_method_ids.end(), entry.first); bool active = active_iter != active_input_method_ids.end(); - bool enabled = - base::ContainsValue(enabled_extension_imes, extra_iter->first); + bool enabled = base::ContainsValue(enabled_extension_imes, entry.first); if (active && !enabled) active_input_method_ids.erase(active_iter); if (!active && enabled) - active_input_method_ids.push_back(extra_iter->first); + active_input_method_ids.push_back(entry.first); if (active == !enabled) active_imes_changed = true; @@ -822,7 +807,7 @@ return; } - std::vector<std::string>::const_iterator iter = + const auto iter = std::find(active_input_method_ids.begin(), active_input_method_ids.end(), last_used_input_method.id()); if (iter == active_input_method_ids.end()) { @@ -835,9 +820,9 @@ void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethodInternal( const std::vector<std::string>& input_method_ids, - const std::string& current_input_methodid) { - std::vector<std::string>::const_iterator iter = std::find( - input_method_ids.begin(), input_method_ids.end(), current_input_methodid); + const std::string& current_input_method_id) { + auto iter = std::find(input_method_ids.begin(), input_method_ids.end(), + current_input_method_id); if (iter != input_method_ids.end()) ++iter; if (iter == input_method_ids.end()) @@ -1098,8 +1083,8 @@ extension_ime_util::GetExtensionIDFromInputMethodID(descriptor.id()); const std::string& component_id = extension_ime_util::GetComponentIDByInputMethodID(descriptor.id()); - if (engine_map_.find(profile) == engine_map_.end() || - engine_map_[profile].find(extension_id) == engine_map_[profile].end()) { + if (!engine_map_.count(profile) || + !engine_map_[profile].count(extension_id)) { LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS()) << "IMEEngine for \"" << extension_id << "\" is not registered"; }
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.cc b/chrome/browser/chromeos/login/demo_mode/demo_session.cc index b8a59f1..cd42564 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_session.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
@@ -503,6 +503,9 @@ } break; case session_manager::SessionState::ACTIVE: + if (ShouldRemoveSplashScreen()) + RemoveSplashScreen(); + // SystemTrayClient may not exist in unit tests. if (SystemTrayClient::Get() && base::FeatureList::IsEnabled( @@ -551,6 +554,15 @@ splash_screen_removed_ = true; } +bool DemoSession::ShouldRemoveSplashScreen() { + // TODO(crbug.com/934979): Launch screensaver after active session starts, so + // that there's no need to check session state here. + return base::FeatureList::IsEnabled(switches::kShowSplashScreenInDemoMode) && + session_manager::SessionManager::Get()->session_state() == + session_manager::SessionState::ACTIVE && + screensaver_activated_; +} + void DemoSession::OnExtensionInstalled(content::BrowserContext* browser_context, const extensions::Extension* extension, bool is_update) { @@ -564,11 +576,11 @@ } void DemoSession::OnAppWindowActivated(extensions::AppWindow* app_window) { - if (!base::FeatureList::IsEnabled(switches::kShowSplashScreenInDemoMode) || - app_window->extension_id() != GetScreensaverAppId()) { + if (app_window->extension_id() != GetScreensaverAppId()) return; - } - RemoveSplashScreen(); + screensaver_activated_ = true; + if (ShouldRemoveSplashScreen()) + RemoveSplashScreen(); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.h b/chrome/browser/chromeos/login/demo_mode/demo_session.h index cac8b84f..a161db1 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_session.h +++ b/chrome/browser/chromeos/login/demo_mode/demo_session.h
@@ -182,6 +182,11 @@ // Removes the splash screen. void RemoveSplashScreen(); + // Returns whether splash screen should be removed. The splash screen should + // be removed when both active session starts (i.e. login screen is destroyed) + // and screensaver is shown, to ensure a smooth transition. + bool ShouldRemoveSplashScreen(); + // session_manager::SessionManagerObserver: void OnSessionStateChanged() override; @@ -222,6 +227,7 @@ std::unique_ptr<base::OneShotTimer> remove_splash_screen_fallback_timer_; bool splash_screen_removed_ = false; + bool screensaver_activated_ = false; base::WeakPtrFactory<DemoSession> weak_ptr_factory_{this};
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc index 1fa3a5f..b4c0c6b 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc
@@ -421,7 +421,8 @@ demo_session->resources()->GetAbsolutePath(base::FilePath("foo.txt"))); } -TEST_F(DemoSessionTest, ShowSplashScreenUntilScreensaverShown) { +// TODO(crbug.com/939687): Reenable the test. +TEST_F(DemoSessionTest, DISABLED_ShowAndRemoveSplashScreen) { DemoSession* demo_session = DemoSession::StartIfInDemoMode(); ASSERT_TRUE(demo_session); @@ -461,16 +462,23 @@ screensaver_app.get()); demo_session->OnAppWindowActivated(app_window); wallpaper_controller_client_->FlushForTesting(); + // The splash screen is not removed until active session starts. + EXPECT_EQ(1, test_wallpaper_controller_.show_always_on_top_wallpaper_count()); + EXPECT_EQ(0, + test_wallpaper_controller_.remove_always_on_top_wallpaper_count()); + session_manager_->SetSessionState(session_manager::SessionState::ACTIVE); + wallpaper_controller_client_->FlushForTesting(); EXPECT_EQ(1, test_wallpaper_controller_.show_always_on_top_wallpaper_count()); EXPECT_EQ(1, test_wallpaper_controller_.remove_always_on_top_wallpaper_count()); - app_window->OnNativeClose(); - - // The timer is cleared after splash screen is removed by the screensaver. + // The timer is cleared after splash screen is removed. EXPECT_FALSE(demo_session->GetTimerForTesting()); + + app_window->OnNativeClose(); } -TEST_F(DemoSessionTest, ShowSplashScreenUntilTimeout) { +// TODO(crbug.com/939687): Reenable the test. +TEST_F(DemoSessionTest, DISABLED_RemoveSplashScreenWhenTimeout) { DemoSession* demo_session = DemoSession::StartIfInDemoMode(); ASSERT_TRUE(demo_session); @@ -523,6 +531,13 @@ EXPECT_EQ(1, test_wallpaper_controller_.show_always_on_top_wallpaper_count()); EXPECT_EQ(1, test_wallpaper_controller_.remove_always_on_top_wallpaper_count()); + // Entering active session will not trigger splash screen removal anymore. + session_manager_->SetSessionState(session_manager::SessionState::ACTIVE); + wallpaper_controller_client_->FlushForTesting(); + EXPECT_EQ(1, test_wallpaper_controller_.show_always_on_top_wallpaper_count()); + EXPECT_EQ(1, + test_wallpaper_controller_.remove_always_on_top_wallpaper_count()); + app_window->OnNativeClose(); }
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc index 42af883..9e68965 100644 --- a/chrome/browser/chromeos/login/kiosk_browsertest.cc +++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -6,6 +6,7 @@ #include <vector> #include "apps/test/app_window_waiter.h" +#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/wallpaper.mojom.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -20,6 +21,7 @@ #include "base/system/sys_info.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/app_mode/fake_cws.h" +#include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h" @@ -49,7 +51,6 @@ #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/ash/wallpaper_controller_client.h" -#include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" @@ -63,6 +64,7 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/web_ui.h" +#include "content/public/common/service_manager_connection.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "extensions/browser/app_window/app_window.h" @@ -84,6 +86,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "services/audio/public/cpp/fake_system_info.h" #include "services/identity/public/cpp/identity_manager.h" +#include "services/service_manager/public/cpp/connector.h" #include "ui/aura/window.h" #include "ui/base/accelerators/accelerator.h" #include "ui/keyboard/public/keyboard_switches.h" @@ -206,14 +209,6 @@ const char kTestClientId[] = "fake-client-id"; const char kTestAppScope[] = "https://www.googleapis.com/auth/userinfo.profile"; -// Test JS API. -const char kLaunchAppForTestNewAPI[] = - "login.AccountPickerScreen.runAppForTesting"; -const char kLaunchAppForTestOldAPI[] = "login.AppsMenuButton.runAppForTesting"; -const char kCheckDiagnosticModeNewAPI[] = "$('oobe').confirmDiagnosticMode_"; -const char kCheckDiagnosticModeOldAPI[] = - "$('show-apps-button').confirmDiagnosticMode_"; - // Helper function for GetConsumerKioskAutoLaunchStatusCallback. void ConsumerKioskAutoLaunchStatusCheck( KioskAppManager::ConsumerKioskAutoLaunchStatus* out_status, @@ -459,6 +454,22 @@ public: KioskTest() : settings_helper_(false), fake_cws_(new FakeCWS) { set_exit_when_last_browser_closes(false); + + // This test does not operate any real App, so App data does not exist. + // Depending on timing, the asynchronous check for app data may or may not + // complete before test checks pass. And if the check does complete, it will + // mark app status KioskAppData::STATUS_ERROR, and exclude it from the list + // of populated apps. + // + // Then, any Update UI event (asynchronous) (like + // LoginDisplayHostCommon::OnStartSignInScreenCommon() will invoke + // SendKioskApps() and destroy test configuration. + // + // We default to ignore test data, as most of test cases use app ids only, + // So individual checks should revert it to default when needed. + // + // TODO(https://crbug.com/937244): Remove this. + KioskAppData::SetIgnoreKioskAppDataLoadFailuresForTesting(true); } ~KioskTest() override {} @@ -515,11 +526,18 @@ command_line->AppendSwitch(switches::kEnableConsumerKiosk); } - void LaunchApp(const std::string& app_id, bool diagnostic_mode) { - bool new_kiosk_ui = KioskAppMenuHandler::EnableNewKioskUI(); - GetLoginUI()->CallJavascriptFunctionUnsafe( - new_kiosk_ui ? kLaunchAppForTestNewAPI : kLaunchAppForTestOldAPI, - base::Value(app_id), base::Value(diagnostic_mode)); + bool LaunchApp(const std::string& app_id, bool diagnostic_mode) { + // TODO(https://crbug.com/932323): Implement or remove diagnostic mode. + if (diagnostic_mode) + return false; + ash::mojom::LoginScreenTestApiPtr test_api_; + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindInterface(ash::mojom::kServiceName, &test_api_); + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + bool found; + login_screen.LaunchApp(app_id, &found); + return found; } void ReloadKioskApps() { @@ -536,10 +554,10 @@ } void SetupTestAppUpdateCheck() { - if (!test_app_version().empty()) { - fake_cws_->SetUpdateCrx(test_app_id(), test_crx_file(), - test_app_version()); - } + if (test_app_version().empty()) + return; + + fake_cws_->SetUpdateCrx(test_app_id(), test_crx_file(), test_app_version()); } void ReloadAutolaunchKioskApps() { @@ -558,18 +576,10 @@ chromeos::WizardController::SkipPostLoginScreensForTesting(); chromeos::WizardController* wizard_controller = chromeos::WizardController::default_controller(); - if (wizard_controller) { + if (wizard_controller) wizard_controller->SkipToLoginForTesting(LoginScreenContext()); - OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait(); - } else { - // No wizard and running with an existing profile and it should land - // on account picker when new kiosk UI is enabled. Otherwise, just - // wait for the login signal from Gaia. - if (KioskAppMenuHandler::EnableNewKioskUI()) - OobeScreenWaiter(OobeScreen::SCREEN_ACCOUNT_PICKER).Wait(); - else - OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait(); - } + + OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait(); } void PrepareAppLaunch() { @@ -590,7 +600,7 @@ if (!network_setup_cb.is_null()) network_setup_cb.Run(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); } const extensions::Extension* GetInstalledApp() { @@ -978,20 +988,19 @@ chromeos::KioskAppLaunchError::Get()); } -IN_PROC_BROWSER_TEST_F(KioskTest, LaunchInDiagnosticMode) { +// TODO: https://crbug.com/932323 +IN_PROC_BROWSER_TEST_F(KioskTest, DISABLED_LaunchInDiagnosticMode) { + const char kCheckDiagnosticModeOldAPI[] = + "$('show-apps-button').confirmDiagnosticMode_"; + PrepareAppLaunch(); SimulateNetworkOnline(); - LaunchApp(kTestKioskApp, true); + EXPECT_TRUE(LaunchApp(kTestKioskApp, true)); - bool new_kiosk_ui = KioskAppMenuHandler::EnableNewKioskUI(); - test::OobeJS() - .CreateWaiter(new_kiosk_ui ? kCheckDiagnosticModeNewAPI - : kCheckDiagnosticModeOldAPI) - ->Wait(); + test::OobeJS().CreateWaiter(kCheckDiagnosticModeOldAPI)->Wait(); - std::string diagnosticMode(new_kiosk_ui ? - kCheckDiagnosticModeNewAPI : kCheckDiagnosticModeOldAPI); + std::string diagnosticMode(kCheckDiagnosticModeOldAPI); test::OobeJS().Evaluate( "(function() {" "var e = new Event('click');" + @@ -1196,7 +1205,9 @@ #if defined(ADDRESS_SANITIZER) #define MAYBE_DoNotLaunchWhenUntrusted DISABLED_DoNotLaunchWhenUntrusted #else -#define MAYBE_DoNotLaunchWhenUntrusted DoNotLaunchWhenUntrusted +// TODO(https://crbug.com/934109): Fix kiosk launch when the device is +// untrusted. +#define MAYBE_DoNotLaunchWhenUntrusted DISABLED_DoNotLaunchWhenUntrusted #endif IN_PROC_BROWSER_TEST_F(KioskTest, MAYBE_DoNotLaunchWhenUntrusted) { PrepareAppLaunch(); @@ -1207,7 +1218,7 @@ CrosSettingsProvider::PERMANENTLY_UNTRUSTED); // Check that the attempt to start a kiosk app fails with an error. - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); bool ignored = false; EXPECT_TRUE(content::ExecuteScriptAndExtractBool( GetLoginUI()->GetWebContents(), @@ -1405,7 +1416,7 @@ set_test_crx_file(crx_file); PrepareAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ(version, GetInstalledAppVersion().GetString()); } @@ -1426,7 +1437,7 @@ // Launch the primary app. StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchWithOptions(false, true); // Verify the primary app and the secondary apps are all installed. @@ -1583,7 +1594,7 @@ set_test_app_id(kTestOfflineEnabledKioskApp); StartUIForAppLaunch(); SimulateNetworkOffline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString()); @@ -1604,7 +1615,7 @@ KioskAppManager::Get()->HasCachedCrx(kTestOfflineEnabledKioskApp)); StartUIForAppLaunch(); SimulateNetworkOffline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString()); @@ -1632,7 +1643,7 @@ StartUIForAppLaunch(); SimulateNetworkOffline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); // v2 app should have been installed. @@ -1651,7 +1662,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString()); @@ -1670,7 +1681,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); @@ -1687,7 +1698,7 @@ set_test_app_id(kTestOfflineEnabledKioskApp); StartUIForAppLaunch(); SimulateNetworkOffline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString()); @@ -1715,7 +1726,7 @@ set_test_app_id(kTestOfflineEnabledKioskApp); StartUIForAppLaunch(); SimulateNetworkOffline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); } @@ -1842,7 +1853,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); @@ -1904,7 +1915,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString()); @@ -1926,7 +1937,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); @@ -1950,7 +1961,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchSuccess(); EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); @@ -1981,7 +1992,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchWithOptions(false, true); // Verify the secondary app kTestSecondaryApp1 is removed. @@ -2009,7 +2020,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchWithOptions(false, true); // Verify the secondary app kTestSecondaryApp3 is installed. @@ -2044,7 +2055,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchWithOptions(false, true); // Verify the secondary app is removed. @@ -2077,7 +2088,7 @@ StartUIForAppLaunch(); SimulateNetworkOnline(); - LaunchApp(test_app_id(), false); + EXPECT_TRUE(LaunchApp(test_app_id(), false)); WaitForAppLaunchWithOptions(false, true); // Verify the shared module is updated to the new version after primary app @@ -2198,7 +2209,7 @@ ""); PrepareAppLaunch(); - LaunchApp(kTestEnterpriseKioskApp, false); + EXPECT_TRUE(LaunchApp(kTestEnterpriseKioskApp, false)); KioskSessionInitializedWaiter().Wait(); @@ -2268,7 +2279,7 @@ waiter.WaitForAppData(); PrepareAppLaunch(); - LaunchApp(kTestEnterpriseKioskApp, false); + EXPECT_TRUE(LaunchApp(kTestEnterpriseKioskApp, false)); WaitForAppLaunchWithOptions(false /* check_launch_data */, true /* terminate_app */);
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc index 6aca187..4af64ab 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h" +#include <cstdint> #include <string> #include "ash/public/cpp/ash_switches.h" @@ -35,16 +36,6 @@ namespace chromeos { namespace { -// Helper to use inside a loop instead of using RunLoop::RunUntilIdle() to avoid -// the loop being a busy loop that prevents renderer from doing its job. Use -// only when there is no better way to synchronize. -void GiveItSomeTime(base::TimeDelta delta) { - base::RunLoop run_loop; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitClosure(), delta); - run_loop.Run(); -} - bool IsScreenLockerLocked() { return ScreenLocker::default_screen_locker() && ScreenLocker::default_screen_locker()->locked(); @@ -137,23 +128,18 @@ return IsScreenLockerLocked() && is_ui_shown; } -bool ScreenLockerTester::IsRestartButtonShown() { +bool ScreenLockerTester::IsLockRestartButtonShown() { if (!IsScreenLockerLocked()) return false; - ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); - bool is_restart_button_shown; - login_screen.IsRestartButtonShown(&is_restart_button_shown); - return IsScreenLockerLocked() && is_restart_button_shown; + return login_screen_tester_.IsRestartButtonShown() && IsScreenLockerLocked(); } -bool ScreenLockerTester::IsShutdownButtonShown() { +bool ScreenLockerTester::IsLockShutdownButtonShown() { if (!IsScreenLockerLocked()) return false; - ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); - bool is_shutdown_button_shown; - login_screen.IsShutdownButtonShown(&is_shutdown_button_shown); + bool is_shutdown_button_shown = login_screen_tester_.IsShutdownButtonShown(); return IsScreenLockerLocked() && is_shutdown_button_shown; } @@ -165,17 +151,11 @@ } int64_t ScreenLockerTester::GetUiUpdateCount() { - ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); - int64_t ui_update_count = 0; - login_screen.GetUiUpdateCount(&ui_update_count); - return ui_update_count; + return login_screen_tester_.GetUiUpdateCount(); } -// Blocks until LoginShelfView::ui_update_count() is greater then -// |previous_update_count|. void ScreenLockerTester::WaitForUiUpdate(int64_t previous_update_count) { - while (GetUiUpdateCount() <= previous_update_count) { - GiveItSomeTime(base::TimeDelta::FromMilliseconds(100)); - } + login_screen_tester_.WaitForUiUpdate(previous_update_count); } + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_tester.h b/chrome/browser/chromeos/login/lock/screen_locker_tester.h index 179e653..bcd9044b 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker_tester.h +++ b/chrome/browser/chromeos/login/lock/screen_locker_tester.h
@@ -9,6 +9,7 @@ #include <string> #include "ash/public/interfaces/login_screen_test_api.test-mojom.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" class AccountId; @@ -31,23 +32,21 @@ bool IsLocked(); // Returns true if Restart button is visible. - bool IsRestartButtonShown(); + bool IsLockRestartButtonShown(); // Returns true if Shutdown button is visible. - bool IsShutdownButtonShown(); + bool IsLockShutdownButtonShown(); // Enters and submits the given password for the given account. void UnlockWithPassword(const AccountId& account_id, const std::string& password); - // Returns LoginShelfView update count. + // LoginScreenTester proxy methods: int64_t GetUiUpdateCount(); - - // Blocks until LoginShelfView::ui_update_count() is creater then - // |previous_update_count|. void WaitForUiUpdate(int64_t previous_update_count); private: + test::LoginScreenTester login_screen_tester_; ash::mojom::LoginScreenTestApiPtr test_api_; DISALLOW_COPY_AND_ASSIGN(ScreenLockerTester);
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc index 199241e..5317c05 100644 --- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc +++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/login/test/js_checker.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h" @@ -264,7 +265,7 @@ ->GetActiveInputMethodIds()); // Switch to Gaia. - test::OobeJS().Evaluate("$('add-user-button').click()"); + ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton()); OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait(); CheckGaiaKeyboard();
diff --git a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc index 845144c7..755de0b6 100644 --- a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc +++ b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/startup_utils.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" @@ -109,9 +110,7 @@ { OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_GAIA_SIGNIN); ProxyAuthDialogWaiter auth_dialog_waiter; - ASSERT_TRUE(content::ExecuteScript( - LoginDisplayHost::default_host()->GetOobeWebContents(), - "$('add-user-button').click()")); + ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton()); screen_waiter.Wait(); auth_dialog_waiter.Wait(); ASSERT_TRUE(auth_dialog_waiter.login_handler());
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index d1f5a66..ff4c845 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -36,6 +36,7 @@ #include "chrome/browser/chromeos/login/test/https_forwarder.h" #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" #include "chrome/browser/chromeos/login/test/oobe_base_test.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" @@ -1181,8 +1182,8 @@ GetLoginUI()->GetWebContents(), "$('gaia-signin').gaiaAuthHost_.addEventListener('ready', function() {" " window.domAutomationController.send('ready');" - "});" - "$('add-user-button').click();")); + "});")); + ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton()); content::DOMMessageQueue message_queue; std::string message; ASSERT_TRUE(message_queue.WaitForMessage(&message)); @@ -1193,13 +1194,20 @@ login_screen_load_observer_->Wait(); ASSERT_TRUE( content::ExecuteScript(GetLoginUI()->GetWebContents(), - "$('saml-interstitial').addEventListener(" - " 'samlInterstitialPageReady'," - " function() {" - " window.domAutomationController.send(" - " 'samlInterstitialPageReady');" - " });" - "$('add-user-button').click();")); + "{" + " let notify = function() {" + " window.domAutomationController.send(" + " 'samlInterstitialPageReady');" + " };" + " if($('gaia-signin')." + " samlInterstitialPageReady) {" + " window.setTimeout(notify,0);" + " } else {" + " $('saml-interstitial').addEventListener(" + " 'samlInterstitialPageReady', notify);" + " }" + "}")); + ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton()); content::DOMMessageQueue message_queue; std::string message;
diff --git a/chrome/browser/chromeos/login/screens/core_oobe_view.h b/chrome/browser/chromeos/login/screens/core_oobe_view.h index 9e6a4e6..57dcfde1 100644 --- a/chrome/browser/chromeos/login/screens/core_oobe_view.h +++ b/chrome/browser/chromeos/login/screens/core_oobe_view.h
@@ -35,7 +35,6 @@ virtual void ClearErrors() = 0; virtual void ReloadContent(const base::DictionaryValue& dictionary) = 0; virtual void ReloadEulaContent(const base::DictionaryValue& dictionary) = 0; - virtual void ShowControlBar(bool show) = 0; virtual void SetVirtualKeyboardShown(bool shown) = 0; virtual void SetClientAreaSize(int width, int height) = 0; virtual void ShowDeviceResetScreen() = 0;
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc index ab79259..a188264a 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc
@@ -6,9 +6,7 @@ #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" -#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" -#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/signin/identity_manager_factory.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" namespace chromeos { @@ -17,9 +15,7 @@ : BrowserContextKeyedServiceFactory( "OAuth2LoginManager", BrowserContextDependencyManager::GetInstance()) { - DependsOn(SigninManagerFactory::GetInstance()); - DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); - DependsOn(GaiaCookieManagerServiceFactory::GetInstance()); + DependsOn(IdentityManagerFactory::GetInstance()); } OAuth2LoginManagerFactory::~OAuth2LoginManagerFactory() {}
diff --git a/chrome/browser/chromeos/login/test/fake_gaia_mixin.cc b/chrome/browser/chromeos/login/test/fake_gaia_mixin.cc index ec68ef8..c38dc0c 100644 --- a/chrome/browser/chromeos/login/test/fake_gaia_mixin.cc +++ b/chrome/browser/chromeos/login/test/fake_gaia_mixin.cc
@@ -104,4 +104,8 @@ } } +void FakeGaiaMixin::TearDownOnMainThread() { + EXPECT_TRUE(gaia_https_forwarder_.Stop()); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/fake_gaia_mixin.h b/chrome/browser/chromeos/login/test/fake_gaia_mixin.h index 867762f..3092eddb 100644 --- a/chrome/browser/chromeos/login/test/fake_gaia_mixin.h +++ b/chrome/browser/chromeos/login/test/fake_gaia_mixin.h
@@ -77,6 +77,7 @@ void SetUp() override; void SetUpCommandLine(base::CommandLine* command_line) override; void SetUpOnMainThread() override; + void TearDownOnMainThread() override; private: net::EmbeddedTestServer* embedded_test_server_;
diff --git a/chrome/browser/chromeos/login/test/https_forwarder.cc b/chrome/browser/chromeos/login/test/https_forwarder.cc index 67c285f..90c75e4 100644 --- a/chrome/browser/chromeos/login/test/https_forwarder.cc +++ b/chrome/browser/chromeos/login/test/https_forwarder.cc
@@ -120,4 +120,8 @@ return forwarding_server_->Start(); } +bool HTTPSForwarder::Stop() { + return forwarding_server_->Stop(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/https_forwarder.h b/chrome/browser/chromeos/login/test/https_forwarder.h index a04a5fd..9a454fdb 100644 --- a/chrome/browser/chromeos/login/test/https_forwarder.h +++ b/chrome/browser/chromeos/login/test/https_forwarder.h
@@ -36,6 +36,8 @@ bool Initialize(const std::string& ssl_host, const GURL& forward_target) WARN_UNUSED_RESULT; + bool Stop() WARN_UNUSED_RESULT; + private: std::string ssl_host_;
diff --git a/chrome/browser/chromeos/login/test/login_screen_tester.cc b/chrome/browser/chromeos/login/test/login_screen_tester.cc new file mode 100644 index 0000000..3b8052f7a --- /dev/null +++ b/chrome/browser/chromeos/login/test/login_screen_tester.cc
@@ -0,0 +1,59 @@ +// Copyright 2019 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/chromeos/login/test/login_screen_tester.h" + +#include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h" +#include "content/public/common/service_manager_connection.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace chromeos { +namespace test { + +LoginScreenTester::LoginScreenTester() { + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindInterface(ash::mojom::kServiceName, &test_api_); +} + +LoginScreenTester::~LoginScreenTester() = default; + +int64_t LoginScreenTester::GetUiUpdateCount() { + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + int64_t ui_update_count = 0; + login_screen.GetUiUpdateCount(&ui_update_count); + return ui_update_count; +} + +bool LoginScreenTester::IsRestartButtonShown() { + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + bool is_restart_button_shown; + login_screen.IsRestartButtonShown(&is_restart_button_shown); + return is_restart_button_shown; +} + +bool LoginScreenTester::IsShutdownButtonShown() { + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + bool is_shutdown_button_shown; + login_screen.IsShutdownButtonShown(&is_shutdown_button_shown); + return is_shutdown_button_shown; +} + +bool LoginScreenTester::ClickAddUserButton() { + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + bool success; + login_screen.ClickAddUserButton(&success); + return success; +} + +bool LoginScreenTester::WaitForUiUpdate(int64_t previous_update_count) { + ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get()); + bool success; + login_screen.WaitForUiUpdate(previous_update_count, &success); + return success; +} + +} // namespace test +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/login_screen_tester.h b/chrome/browser/chromeos/login/test/login_screen_tester.h new file mode 100644 index 0000000..957ec4a --- /dev/null +++ b/chrome/browser/chromeos/login/test/login_screen_tester.h
@@ -0,0 +1,43 @@ +// Copyright 2019 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_CHROMEOS_LOGIN_TEST_LOGIN_SCREEN_TESTER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_LOGIN_SCREEN_TESTER_H_ + +#include <cstdint> + +#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h" +#include "base/macros.h" + +namespace chromeos { +namespace test { + +// High-level API to ash::mojom::LoginScreenTestApi. +class LoginScreenTester { + public: + LoginScreenTester(); + ~LoginScreenTester(); + + // Blocking mojo calls. + int64_t GetUiUpdateCount(); + bool IsRestartButtonShown(); + bool IsShutdownButtonShown(); + + // Returns true on success (i.e. button is not disabled). + bool ClickAddUserButton(); + + // Blocks until LoginShelfView::ui_update_count() is greater then + // |previous_update_count|. Returns true on success, false on error. + bool WaitForUiUpdate(int64_t previous_update_count); + + private: + ash::mojom::LoginScreenTestApiPtr test_api_; + + DISALLOW_COPY_AND_ASSIGN(LoginScreenTester); +}; + +} // namespace test +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_LOGIN_SCREEN_TESTER_H_
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc index ee23b45..5f435b8 100644 --- a/chrome/browser/chromeos/login/test/oobe_base_test.cc +++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -125,9 +125,9 @@ } void OobeBaseTest::TearDownOnMainThread() { - EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); - mixin_host_.TearDownOnMainThread(); + // Embedded test server should always be shutdown after any https forwarders. + EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); extensions::ExtensionApiTest::TearDownOnMainThread(); }
diff --git a/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.cc b/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.cc index b558547..3248a54 100644 --- a/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.cc +++ b/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.cc
@@ -4,14 +4,18 @@ #include "chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h" +#include <utility> + #include "ash/public/interfaces/kiosk_app_info.mojom.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_data.h" #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" #include "chrome/browser/ui/ash/login_screen_client.h" +#include "content/public/browser/notification_service.h" #include "extensions/grit/extensions_browser_resources.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image_skia.h" @@ -42,6 +46,16 @@ SendKioskApps(); } +void KioskAppMenuUpdater::OnKioskAppsSet(bool success) { + if (!success) + return; + + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_KIOSK_APPS_LOADED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); +} + void KioskAppMenuUpdater::SendKioskApps() { if (!LoginScreenClient::HasInstance()) return; @@ -81,8 +95,9 @@ } output.push_back(std::move(mojo_app)); } - - LoginScreenClient::Get()->login_screen()->SetKioskApps(std::move(output)); + LoginScreenClient::Get()->login_screen()->SetKioskApps( + std::move(output), base::BindOnce(&KioskAppMenuUpdater::OnKioskAppsSet, + weak_factory_.GetWeakPtr())); KioskAppLaunchError::Error error = KioskAppLaunchError::Get(); if (error == KioskAppLaunchError::NONE)
diff --git a/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h b/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h index 96e092c0..af668605 100644 --- a/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h +++ b/chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_LOGIN_UI_KIOSK_APP_MENU_UPDATER_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" @@ -33,9 +34,14 @@ void OnArcKioskAppsChanged() override; private: + // Mojo SendKioskApps() callback. + void OnKioskAppsSet(bool success); + ScopedObserver<KioskAppManager, KioskAppMenuUpdater> kiosk_observer_; ScopedObserver<ArcKioskAppManager, KioskAppMenuUpdater> arc_kiosk_observer_; + base::WeakPtrFactory<KioskAppMenuUpdater> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(KioskAppMenuUpdater); };
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc index 8e42ed59..4a16485b 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/chromeos/login/arc_kiosk_controller.h" #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" +#include "chrome/browser/chromeos/login/screens/gaia_view.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -267,4 +268,35 @@ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); } +void LoginDisplayHostCommon::OnStartSignInScreenCommon() { + kiosk_updater_.SendKioskApps(); +} + +void LoginDisplayHostCommon::ShowGaiaDialogCommon( + const base::Optional<AccountId>& prefilled_account) { + DCHECK(GetOobeUI()); + + if (prefilled_account) { + // Make sure gaia displays |account| if requested. + if (!GetLoginDisplay()->delegate()->IsSigninInProgress()) + GetOobeUI()->GetGaiaScreenView()->ShowGaiaAsync(prefilled_account); + LoadWallpaper(*prefilled_account); + } else { + // Two criteria here: + // 1) If we have started a wizard other than Gaia signin (signified by the + // current_screen() changing), we need to reload the Gaia screen, otherwise + // dialog_->Show() will show the wrong screen. + // 2) While login is being loaded in, the current_screen is UNKNOWN. During + // this time, the GaiaScreenView is initialized, after which + // ShowGaiaAsync() is called to load up the Gaia screen. If we try to + // ShowGaiaAsync() before this initialization is complete, the Gaia screen + // UI can crash and get stuck. + if (GetOobeUI()->current_screen() != OobeScreen::SCREEN_GAIA_SIGNIN && + GetOobeUI()->current_screen() != OobeScreen::SCREEN_UNKNOWN) { + GetOobeUI()->GetGaiaScreenView()->ShowGaiaAsync(base::nullopt); + } + LoadSigninWallpaper(); + } +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.h b/chrome/browser/chromeos/login/ui/login_display_host_common.h index 140d4b7..0fa53d7 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_common.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_common.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -74,6 +75,12 @@ // Marks display host for deletion. void ShutdownDisplayHost(); + // Common code for OnStartSignInScreen() call above. + void OnStartSignInScreenCommon(); + + // Common code for ShowGaiaDialog() call above. + void ShowGaiaDialogCommon(const base::Optional<AccountId>& prefilled_account); + // Active instance of authentication prewarmer. std::unique_ptr<AuthPrewarmer> auth_prewarmer_; @@ -106,6 +113,8 @@ // Called after host deletion. std::vector<base::OnceClosure> completion_callbacks_; + KioskAppMenuUpdater kiosk_updater_; + base::WeakPtrFactory<LoginDisplayHostCommon> weak_factory_; DISALLOW_COPY_AND_ASSIGN(LoginDisplayHostCommon);
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc index 9fade08..0d6d9ff 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -213,12 +213,12 @@ user_selection_screen_->InitEasyUnlock(); - kiosk_updater_.SendKioskApps(); - system_info_updater_->StartRequest(); // Update status of add user button in the shelf. UpdateAddUserButtonStatus(); + + OnStartSignInScreenCommon(); } void LoginDisplayHostMojo::OnPreferencesChanged() { @@ -248,26 +248,7 @@ if (users_.empty()) can_close_dialog_ = false; - if (prefilled_account) { - // Make sure gaia displays |account| if requested. - if (!login_display_->IsSigninInProgress()) - GetOobeUI()->GetGaiaScreenView()->ShowGaiaAsync(prefilled_account); - LoadWallpaper(*prefilled_account); - } else { - // Two criteria here: - // 1) If we have started a wizard other than Gaia signin (signified by the - // current_screen() changing), we need to reload the Gaia screen, otherwise - // dialog_->Show() will show the wrong screen. 2) While login is being - // loaded in, the current_screen is UNKNOWN. During this time, the - // GaiaScreenView is initialized, after which ShowGaiaAsync() is called to - // load up the Gaia screen. If we try to ShowGaiaAsync() before this - // initialization is complete, the Gaia screen UI can crash and get stuck. - if (GetOobeUI()->current_screen() != OobeScreen::SCREEN_GAIA_SIGNIN && - GetOobeUI()->current_screen() != OobeScreen::SCREEN_UNKNOWN) { - GetOobeUI()->GetGaiaScreenView()->ShowGaiaAsync(base::nullopt); - } - LoadSigninWallpaper(); - } + ShowGaiaDialogCommon(prefilled_account); dialog_->Show(); }
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h index b2d12fb..5c8b37af 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" -#include "chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h" #include "chrome/browser/chromeos/login/ui/login_display_host_common.h" #include "chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h" #include "chrome/browser/ui/ash/login_screen_client.h" @@ -157,8 +156,6 @@ // The account id of the user pod that's being focused. AccountId focused_pod_account_id_; - KioskAppMenuUpdater kiosk_updater_; - // Fetches system information and sends it to the UI over mojo. std::unique_ptr<MojoSystemInfoDispatcher> system_info_updater_;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc index d11c511b..3f4e802d 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -672,6 +672,9 @@ CHECK(login_display_); GetOobeUI()->ShowSigninScreen(context, login_display_.get(), login_display_.get()); + + OnStartSignInScreenCommon(); + TRACE_EVENT_ASYNC_STEP_INTO0("ui", "ShowLoginWebUI", kShowLoginWebUIid, "WaitForScreenStateInitialize"); @@ -1081,7 +1084,10 @@ void LoginDisplayHostWebUI::ShowGaiaDialog( bool can_close, const base::Optional<AccountId>& prefilled_account) { - NOTREACHED(); + // This is a special case, when WebUI sign-in screen shown with Views-based + // launch bar. Then "Add user" button will be Views-based, and user click + // will result in this call. + ShowGaiaDialogCommon(prefilled_account); } void LoginDisplayHostWebUI::HideOobeDialog() {
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index 1369359..8392681 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -400,7 +400,6 @@ if (!GetOobeUI()) return; CoreOobeView* view = GetOobeUI()->GetCoreOobeView(); - view->ShowControlBar(!visible); view->SetVirtualKeyboardShown(visible); }
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index 78f01ea..27646a3 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -2091,7 +2091,6 @@ ASSERT_FALSE(JSExecuteBooleanExpression("$('error-message').hidden")); ASSERT_TRUE(JSExecuteBooleanExpression( "$('error-message').classList.contains('ui-state-local-state-error')")); - ASSERT_TRUE(JSExecuteBooleanExpression("$('login-header-bar').hidden")); // Emulates user click on the "Restart and Powerwash" button. ASSERT_EQ(0, fake_session_manager_client()->start_device_wipe_call_count());
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index 6ff9284..e3f5ec6c 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -2601,6 +2601,8 @@ broker)); } +// TODO(crbug.com/939700): Fix this test. +#if 0 IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, PacHttpsUrlStrippingEnabled) { SetManagedSessionsEnabled(/* managed_sessions_enabled */ true); @@ -2633,6 +2635,7 @@ chromeos::ChromeUserManager::Get()->IsFullManagementDisclosureNeeded( broker)); } +#endif class TermsOfServiceDownloadTest : public DeviceLocalAccountTest, public testing::WithParamInterface<bool> {
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc index db454bd..778935e3 100644 --- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -408,6 +408,7 @@ } ~DeviceStatusCollectorTest() override { + chromeos::PowerManagerClient::Shutdown(); chromeos::LoginState::Shutdown(); chromeos::CrasAudioHandler::Shutdown(); chromeos::KioskAppManager::Shutdown(); @@ -2173,13 +2174,10 @@ : public DeviceStatusCollectorTest { protected: void SetUp() override { - RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo), - base::BindRepeating(&GetEmptyCPUStatistics), - base::BindRepeating(&GetEmptyCPUTempInfo), - base::BindRepeating(&GetEmptyAndroidStatus), - base::BindRepeating(&GetEmptyTpmStatus)); + DeviceStatusCollectorTest::SetUp(); + scoped_testing_cros_settings_.device_settings()->SetBoolean( + chromeos::kReportDeviceNetworkInterfaces, true); - chromeos::DBusThreadManager::Initialize(); chromeos::NetworkHandler::Initialize(); base::RunLoop().RunUntilIdle(); @@ -2288,8 +2286,8 @@ } void TearDown() override { - status_collector_.reset(); chromeos::NetworkHandler::Shutdown(); + DeviceStatusCollectorTest::TearDown(); } void VerifyNetworkReporting() {
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc index 2996280..d764a2f 100644 --- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc +++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
@@ -115,7 +115,10 @@ device_settings_service_->device_off_hours_controller(); } - void TearDown() override { chromeos::SystemClockClient::Shutdown(); } + void TearDown() override { + chromeos::SystemClockClient::Shutdown(); + chromeos::DeviceSettingsTestBase::TearDown(); + } void UpdateDeviceSettings() { device_policy_->Build();
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.cc b/chrome/browser/chromeos/settings/device_settings_test_helper.cc index a12bd017..7e731020 100644 --- a/chrome/browser/chromeos/settings/device_settings_test_helper.cc +++ b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
@@ -38,7 +38,9 @@ DeviceSettingsTestBase::DeviceSettingsTestBase() : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} -DeviceSettingsTestBase::~DeviceSettingsTestBase() = default; +DeviceSettingsTestBase::~DeviceSettingsTestBase() { + CHECK(teardown_called_); +} void DeviceSettingsTestBase::SetUp() { device_policy_ = std::make_unique<policy::DevicePolicyBuilder>(); @@ -66,6 +68,7 @@ } void DeviceSettingsTestBase::TearDown() { + teardown_called_ = true; OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting( nullptr); FlushDeviceSettings();
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.h b/chrome/browser/chromeos/settings/device_settings_test_helper.h index 9f761f4..9025aea5 100644 --- a/chrome/browser/chromeos/settings/device_settings_test_helper.h +++ b/chrome/browser/chromeos/settings/device_settings_test_helper.h
@@ -85,6 +85,8 @@ std::unique_ptr<TestingProfile> profile_; private: + bool teardown_called_ = false; + DISALLOW_COPY_AND_ASSIGN(DeviceSettingsTestBase); };
diff --git a/chrome/browser/chromeos/shutdown_policy_browsertest.cc b/chrome/browser/chromeos/shutdown_policy_browsertest.cc index a9610fbd..28a6bc74 100644 --- a/chrome/browser/chromeos/shutdown_policy_browsertest.cc +++ b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/lock/screen_locker.h" #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" #include "chrome/browser/chromeos/policy/device_policy_builder.h" @@ -49,26 +50,6 @@ namespace chromeos { -namespace { - -const char kWaitForHiddenStateScript[] = - "var screenElement = document.getElementById('%s');" - "var expectation = %s;" - "function SendReplyIfAsExpected() {" - " if (screenElement.hidden != expectation)" - " return false;" - " domAutomationController.send(screenElement.hidden);" - " observer.disconnect();" - " return true;" - "}" - "var observer = new MutationObserver(SendReplyIfAsExpected);" - "if (!SendReplyIfAsExpected()) {" - " var options = { attributes: true };" - " observer.observe(screenElement, options);" - "}"; - -} // namespace - class ShutdownPolicyBaseTest : public policy::DevicePolicyCrosBrowserTest, public DeviceSettingsService::Observer { @@ -97,13 +78,6 @@ MarkAsEnterpriseOwned(); } - // A helper functions which prepares the script by injecting the element_id of - // the element whose hiddenness we want to check and the expectation. - std::string PrepareScript(const std::string& element_id, bool expectation) { - return base::StringPrintf(kWaitForHiddenStateScript, element_id.c_str(), - expectation ? "true" : "false"); - } - // Updates the device shutdown policy and sets it to |reboot_on_shutdown|. void UpdateRebootOnShutdownPolicy(bool reboot_on_shutdown) { policy::DevicePolicyBuilder* builder = device_policy(); @@ -240,8 +214,8 @@ IN_PROC_BROWSER_TEST_F(ShutdownPolicyLockerTest, TestBasic) { ScreenLockerTester tester; - EXPECT_FALSE(tester.IsRestartButtonShown()); - EXPECT_TRUE(tester.IsShutdownButtonShown()); + EXPECT_FALSE(tester.IsLockRestartButtonShown()); + EXPECT_TRUE(tester.IsLockShutdownButtonShown()); } IN_PROC_BROWSER_TEST_F(ShutdownPolicyLockerTest, PolicyChange) { @@ -250,15 +224,15 @@ UpdateRebootOnShutdownPolicy(true); RefreshDevicePolicy(); tester.WaitForUiUpdate(ui_update_count); - EXPECT_TRUE(tester.IsRestartButtonShown()); - EXPECT_FALSE(tester.IsShutdownButtonShown()); + EXPECT_TRUE(tester.IsLockRestartButtonShown()); + EXPECT_FALSE(tester.IsLockShutdownButtonShown()); ui_update_count = tester.GetUiUpdateCount(); UpdateRebootOnShutdownPolicy(false); RefreshDevicePolicy(); tester.WaitForUiUpdate(ui_update_count); - EXPECT_FALSE(tester.IsRestartButtonShown()); - EXPECT_TRUE(tester.IsShutdownButtonShown()); + EXPECT_FALSE(tester.IsLockRestartButtonShown()); + EXPECT_TRUE(tester.IsLockShutdownButtonShown()); } class ShutdownPolicyLoginTest : public ShutdownPolicyBaseTest { @@ -286,8 +260,7 @@ content::NotificationService::AllSources()).Wait(); LoginDisplayHost* host = LoginDisplayHost::default_host(); ASSERT_TRUE(host); - contents_ = host->GetOobeWebContents(); - ASSERT_TRUE(contents_); + ASSERT_TRUE(host->GetOobeWebContents()); // Wait for the login UI to be ready. WaitUntilOobeUIIsReady(host->GetOobeUI()); @@ -302,34 +275,31 @@ } } - // Checks whether the element identified by |element_id| is hidden and only - // returns if the expectation is fulfilled. - void PrepareAndRunScript(const std::string& element_id, bool expectation) { - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - contents_, PrepareScript(element_id, expectation), &result_)); - } - private: - content::WebContents* contents_ = nullptr; - DISALLOW_COPY_AND_ASSIGN(ShutdownPolicyLoginTest); }; IN_PROC_BROWSER_TEST_F(ShutdownPolicyLoginTest, PolicyNotSet) { - PrepareAndRunScript("restart-header-bar-item", true); - PrepareAndRunScript("shutdown-header-bar-item", false); + test::LoginScreenTester tester; + EXPECT_FALSE(tester.IsRestartButtonShown()); + EXPECT_TRUE(tester.IsShutdownButtonShown()); } IN_PROC_BROWSER_TEST_F(ShutdownPolicyLoginTest, PolicyChange) { + test::LoginScreenTester tester; + int ui_update_count = tester.GetUiUpdateCount(); UpdateRebootOnShutdownPolicy(true); RefreshDevicePolicy(); - PrepareAndRunScript("restart-header-bar-item", false); - PrepareAndRunScript("shutdown-header-bar-item", true); + tester.WaitForUiUpdate(ui_update_count); + EXPECT_TRUE(tester.IsRestartButtonShown()); + EXPECT_FALSE(tester.IsShutdownButtonShown()); + ui_update_count = tester.GetUiUpdateCount(); UpdateRebootOnShutdownPolicy(false); RefreshDevicePolicy(); - PrepareAndRunScript("restart-header-bar-item", true); - PrepareAndRunScript("shutdown-header-bar-item", false); + tester.WaitForUiUpdate(ui_update_count); + EXPECT_FALSE(tester.IsRestartButtonShown()); + EXPECT_TRUE(tester.IsShutdownButtonShown()); } } // namespace chromeos
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc index 52a4897a..9116786d 100644 --- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc +++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -18,7 +18,6 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_path_override.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/download/chrome_download_manager_delegate.h" @@ -264,7 +263,7 @@ DownloadConfirmationResult result, const base::FilePath& virtual_path); - base::FilePath GetDefaultDownloadPath() const; + base::FilePath GetDownloadDirectory() const { return test_download_dir_; } TestChromeDownloadManagerDelegate* delegate(); content::MockDownloadManager* download_manager(); DownloadPrefs* download_prefs(); @@ -274,8 +273,7 @@ void GetNextId(uint32_t next_id) { download_ids_.emplace_back(next_id); } private: - base::ScopedPathOverride download_dir_override_{ - chrome::DIR_DEFAULT_DOWNLOADS}; + base::FilePath test_download_dir_; sync_preferences::TestingPrefServiceSyncable* pref_service_; std::unique_ptr<content::MockDownloadManager> download_manager_; std::unique_ptr<TestChromeDownloadManagerDelegate> delegate_; @@ -288,13 +286,18 @@ } void ChromeDownloadManagerDelegateTest::SetUp() { - DownloadPrefs::ReinitializeDefaultDownloadDirectoryForTesting(); ChromeRenderViewHostTestHarness::SetUp(); CHECK(profile()); + + test_download_dir_ = profile()->GetPath().AppendASCII("TestDownloadDir"); + ASSERT_TRUE(base::CreateDirectory(test_download_dir_)); + delegate_ = std::make_unique<::testing::NiceMock<TestChromeDownloadManagerDelegate>>( profile()); + download_prefs()->SkipSanitizeDownloadTargetPathForTesting(); + download_prefs()->SetDownloadPath(test_download_dir_); delegate_->SetDownloadManager(download_manager_.get()); pref_service_ = profile()->GetTestingPrefService(); web_contents()->SetDelegate(&web_contents_delegate_); @@ -357,8 +360,7 @@ base::FilePath ChromeDownloadManagerDelegateTest::GetPathInDownloadDir( const char* relative_path) { - base::FilePath full_path = - GetDefaultDownloadPath().AppendASCII(relative_path); + base::FilePath full_path = GetDownloadDirectory().AppendASCII(relative_path); return full_path.NormalizePathSeparators(); } @@ -406,13 +408,6 @@ return result; } -base::FilePath ChromeDownloadManagerDelegateTest::GetDefaultDownloadPath() - const { - base::FilePath path; - CHECK(base::PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path)); - return path; -} - void ChromeDownloadManagerDelegateTest::OnConfirmationCallbackComplete( const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback, DownloadConfirmationResult result, @@ -603,9 +598,8 @@ TEST_F(ChromeDownloadManagerDelegateTest, CheckForFileExistence) { const char kData[] = "helloworld"; const size_t kDataLength = sizeof(kData) - 1; - base::FilePath existing_path = GetDefaultDownloadPath().AppendASCII("foo"); - base::FilePath non_existent_path = - GetDefaultDownloadPath().AppendASCII("bar"); + base::FilePath existing_path = GetDownloadDirectory().AppendASCII("foo"); + base::FilePath non_existent_path = GetDownloadDirectory().AppendASCII("bar"); base::WriteFile(existing_path, kData, kDataLength); std::unique_ptr<download::MockDownloadItem> download_item =
diff --git a/chrome/browser/download/download_core_service_impl.cc b/chrome/browser/download/download_core_service_impl.cc index 582326f..b857f90e 100644 --- a/chrome/browser/download/download_core_service_impl.cc +++ b/chrome/browser/download/download_core_service_impl.cc
@@ -25,6 +25,10 @@ #include "chrome/browser/extensions/api/downloads/downloads_api.h" #endif +#if defined(OS_ANDROID) +#include "chrome/browser/android/download/download_utils.h" +#endif + using content::BrowserContext; using content::DownloadManager; using content::DownloadManagerDelegate; @@ -64,19 +68,11 @@ new DownloadHistory::HistoryAdapter(history)))); } - download_provider_.reset(new DownloadOfflineContentProvider( - OfflineContentAggregatorFactory::GetForBrowserContext( - profile_->GetOriginalProfile()), - offline_items_collection::OfflineContentAggregator::CreateUniqueNameSpace( - OfflineItemUtils::GetDownloadNamespacePrefix( - profile_->IsOffTheRecord()), - profile_->IsOffTheRecord()))); - // Pass an empty delegate when constructing the DownloadUIController. The // default delegate does all the notifications we need. download_ui_.reset(new DownloadUIController( manager, std::unique_ptr<DownloadUIController::Delegate>(), - download_provider_.get())); + CreateDownloadOfflineContentProvider())); #if !defined(OS_ANDROID) download_shelf_controller_.reset(new DownloadShelfController(profile_)); @@ -90,6 +86,22 @@ return manager_delegate_.get(); } +DownloadOfflineContentProvider* +DownloadCoreServiceImpl::CreateDownloadOfflineContentProvider() { +#if defined(OS_ANDROID) + return DownloadUtils::GetDownloadOfflineContentProvider(profile_); +#else + download_provider_.reset(new DownloadOfflineContentProvider( + OfflineContentAggregatorFactory::GetForBrowserContext( + profile_->GetOriginalProfile()), + offline_items_collection::OfflineContentAggregator::CreateUniqueNameSpace( + OfflineItemUtils::GetDownloadNamespacePrefix( + profile_->IsOffTheRecord()), + profile_->IsOffTheRecord()))); + return download_provider_.get(); +#endif +} + DownloadHistory* DownloadCoreServiceImpl::GetDownloadHistory() { if (!download_manager_created_) { GetDownloadManagerDelegate();
diff --git a/chrome/browser/download/download_core_service_impl.h b/chrome/browser/download/download_core_service_impl.h index 23ee925..894d2ae 100644 --- a/chrome/browser/download/download_core_service_impl.h +++ b/chrome/browser/download/download_core_service_impl.h
@@ -55,6 +55,8 @@ void Shutdown() override; private: + DownloadOfflineContentProvider* CreateDownloadOfflineContentProvider(); + bool download_manager_created_; Profile* profile_;
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc index 679721e..22dcce7 100644 --- a/chrome/browser/download/download_offline_content_provider.cc +++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -198,7 +198,6 @@ if (item->GetState() == DownloadItem::COMPLETE) { // TODO(crbug.com/938152): May be move this to DownloadItem. AddCompletedDownload(item); - return; } UpdateObservers(item); @@ -219,23 +218,23 @@ void DownloadOfflineContentProvider::AddCompletedDownload(DownloadItem* item) { #if defined(OS_ANDROID) - if (!item->GetTargetFilePath().IsContentUri()) { - DownloadManagerBridge::AddCompletedDownload( - item, base::BindOnce( - &DownloadOfflineContentProvider::AddCompletedDownloadDone, - weak_ptr_factory_.GetWeakPtr(), item)); - } else { - AddCompletedDownloadDone(item, -1); - } -#else - AddCompletedDownloadDone(item, -1); + if (completed_downloads_.find(item->GetGuid()) != completed_downloads_.end()) + return; + completed_downloads_.insert(item->GetGuid()); + + DownloadManagerBridge::AddCompletedDownload( + item, + base::BindOnce(&DownloadOfflineContentProvider::AddCompletedDownloadDone, + weak_ptr_factory_.GetWeakPtr(), item)); #endif } void DownloadOfflineContentProvider::AddCompletedDownloadDone( DownloadItem* item, - int64_t system_download_id) { - UpdateObservers(item); + int64_t system_download_id, + bool can_resolve) { + if (can_resolve && item->HasUserGesture()) + item->OpenDownload(); } DownloadItem* DownloadOfflineContentProvider::GetDownload(
diff --git a/chrome/browser/download/download_offline_content_provider.h b/chrome/browser/download/download_offline_content_provider.h index 8a4f9d40..e2acc7d 100644 --- a/chrome/browser/download/download_offline_content_provider.h +++ b/chrome/browser/download/download_offline_content_provider.h
@@ -72,13 +72,16 @@ VisualsCallback callback, const SkBitmap& bitmap); void AddCompletedDownload(DownloadItem* item); - void AddCompletedDownloadDone(DownloadItem* item, int64_t system_download_id); + void AddCompletedDownloadDone(DownloadItem* item, + int64_t system_download_id, + bool can_resolve); void UpdateObservers(DownloadItem* item); base::ObserverList<OfflineContentProvider::Observer>::Unchecked observers_; OfflineContentAggregator* aggregator_; std::string name_space_; DownloadManager* manager_; + std::set<std::string> completed_downloads_; base::WeakPtrFactory<DownloadOfflineContentProvider> weak_ptr_factory_;
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc index f1c854a..884ccbf 100644 --- a/chrome/browser/download/download_prefs.cc +++ b/chrome/browser/download/download_prefs.cc
@@ -277,11 +277,6 @@ } // static -void DownloadPrefs::ReinitializeDefaultDownloadDirectoryForTesting() { - GetDefaultDownloadDirectorySingleton().Initialize(); -} - -// static const base::FilePath& DownloadPrefs::GetDefaultDownloadDirectory() { return GetDefaultDownloadDirectorySingleton().path(); } @@ -433,6 +428,10 @@ SaveAutoOpenState(); } +void DownloadPrefs::SkipSanitizeDownloadTargetPathForTesting() { + skip_sanitize_download_target_path_for_testing_ = true; +} + void DownloadPrefs::SaveAutoOpenState() { std::string extensions; for (auto it = auto_open_.begin(); it != auto_open_.end(); ++it) { @@ -453,6 +452,9 @@ base::FilePath DownloadPrefs::SanitizeDownloadTargetPath( const base::FilePath& path) const { #if defined(OS_CHROMEOS) + if (skip_sanitize_download_target_path_for_testing_) + return path; + base::FilePath migrated_drive_path; // Managed prefs may force a legacy Drive path as the download path. Ensure // the path is valid when DriveFS is enabled.
diff --git a/chrome/browser/download/download_prefs.h b/chrome/browser/download/download_prefs.h index 7e7f0ea..351a9b0 100644 --- a/chrome/browser/download/download_prefs.h +++ b/chrome/browser/download/download_prefs.h
@@ -46,8 +46,6 @@ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - static void ReinitializeDefaultDownloadDirectoryForTesting(); - // Returns the default download directory. static const base::FilePath& GetDefaultDownloadDirectory(); @@ -116,6 +114,10 @@ void ResetAutoOpen(); + // If this is called, the download target path will not be sanitized going + // forward - whatever has been passed to SetDownloadPath will be used. + void SkipSanitizeDownloadTargetPathForTesting(); + private: void SaveAutoOpenState(); @@ -152,6 +154,10 @@ bool should_open_pdf_in_system_reader_; #endif + // If this is true, SanitizeDownloadTargetPath will always return the passed + // path verbatim. + bool skip_sanitize_download_target_path_for_testing_ = false; + DISALLOW_COPY_AND_ASSIGN(DownloadPrefs); };
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc index 1a616604..b09367b 100644 --- a/chrome/browser/download/download_target_determiner_unittest.cc +++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -8,7 +8,6 @@ #include <string> #include <vector> -#include "base/at_exit.h" #include "base/bind.h" #include "base/files/file_path.h" #include "base/location.h" @@ -19,7 +18,6 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_path_override.h" #include "base/threading/thread_task_runner_handle.h" #include "base/value_conversions.h" #include "build/build_config.h" @@ -289,11 +287,7 @@ void VerifyDownloadTarget(const DownloadTestCase& test_case, const DownloadTargetInfo* target_info); - base::FilePath test_download_dir() const { - base::FilePath path; - CHECK(base::PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path)); - return path; - } + base::FilePath test_download_dir() const { return test_download_dir_; } const base::FilePath& test_virtual_dir() const { return test_virtual_dir_; @@ -310,10 +304,7 @@ private: void SetUpFileTypePolicies(); - // Resets the global cached DefaultDownloadDirectory instance. - base::ShadowingAtExitManager at_exit_manager_; - base::ScopedPathOverride download_dir_override_{ - chrome::DIR_DEFAULT_DOWNLOADS}; + base::FilePath test_download_dir_; std::unique_ptr<DownloadPrefs> download_prefs_; ::testing::NiceMock<MockDownloadTargetDeterminerDelegate> delegate_; NullWebContentsDelegate web_contents_delegate_; @@ -326,10 +317,14 @@ void DownloadTargetDeterminerTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); CHECK(profile()); - download_prefs_.reset(new DownloadPrefs(profile())); + + test_download_dir_ = profile()->GetPath().AppendASCII("TestDownloadDir"); + + download_prefs_ = std::make_unique<DownloadPrefs>(profile()); + download_prefs_->SkipSanitizeDownloadTargetPathForTesting(); + download_prefs_->SetDownloadPath(test_download_dir()); web_contents()->SetDelegate(&web_contents_delegate_); test_virtual_dir_ = test_download_dir().Append(FILE_PATH_LITERAL("virtual")); - download_prefs_->SetDownloadPath(test_download_dir()); delegate_.SetupDefaults(); SetUpFileTypePolicies(); #if defined(OS_ANDROID) @@ -2383,7 +2378,7 @@ : public DownloadTargetDeterminerTest { public: DownloadTargetDeterminerTestWithPlugin() - : old_plugin_service_filter_(NULL) {} + : old_plugin_service_filter_(nullptr) {} void SetUp() override { DownloadTargetDeterminerTest::SetUp(); @@ -2434,8 +2429,8 @@ { ForceRefreshOfPlugins(); std::vector<content::WebPluginInfo> info; - ASSERT_FALSE(plugin_service->GetPluginInfoArray( - GURL(), kTestMIMEType, false, &info, NULL)); + ASSERT_FALSE(plugin_service->GetPluginInfoArray(GURL(), kTestMIMEType, + false, &info, nullptr)); ASSERT_EQ(0u, info.size()) << "Name: " << info[0].name << ", Path: " << info[0].path.value(); } @@ -2503,8 +2498,8 @@ { ForceRefreshOfPlugins(); std::vector<content::WebPluginInfo> info; - ASSERT_FALSE(plugin_service->GetPluginInfoArray( - GURL(), kTestMIMEType, false, &info, NULL)); + ASSERT_FALSE(plugin_service->GetPluginInfoArray(GURL(), kTestMIMEType, + false, &info, nullptr)); ASSERT_EQ(0u, info.size()) << "Name: " << info[0].name << ", Path: " << info[0].path.value(); }
diff --git a/chrome/browser/download/offline_item_utils.cc b/chrome/browser/download/offline_item_utils.cc index d9fce380..3e72fb6 100644 --- a/chrome/browser/download/offline_item_utils.cc +++ b/chrome/browser/download/offline_item_utils.cc
@@ -60,9 +60,10 @@ OfflineItem OfflineItemUtils::CreateOfflineItem(const std::string& name_space, DownloadItem* download_item) { + auto* browser_context = + content::DownloadItemUtils::GetBrowserContext(download_item); bool off_the_record = - content::DownloadItemUtils::GetBrowserContext(download_item) - ->IsOffTheRecord(); + browser_context ? browser_context->IsOffTheRecord() : false; OfflineItem item; item.id = ContentId(name_space, download_item->GetGuid()); @@ -80,6 +81,7 @@ item.is_openable = download_item->CanOpenDownload(); item.file_path = download_item->GetTargetFilePath(); item.mime_type = download_item->GetMimeType(); + // TODO(shaktisahu): Handle any null or generic mime types. item.page_url = download_item->GetTabUrl(); item.original_url = download_item->GetOriginalUrl();
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index 58e27e6..1e3cd80 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -7,6 +7,7 @@ #include "base/path_service.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" @@ -17,11 +18,14 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/api/automation_internal.h" #include "chrome/common/extensions/chrome_extension_messages.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/ax_event_notification_details.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "extensions/test/extension_test_message_listener.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -69,10 +73,18 @@ } public: + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + features::kExperimentalAccessibilityLabels); + ExtensionApiTest::SetUp(); + } + void SetUpOnMainThread() override { ExtensionApiTest::SetUpOnMainThread(); host_resolver()->AddRule("*", "127.0.0.1"); } + + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(AutomationApiTest, TestRendererAccessibilityEnabled) { @@ -102,6 +114,34 @@ << message_; } +IN_PROC_BROWSER_TEST_F(AutomationApiTest, ImageLabels) { + StartEmbeddedTestServer(); + const GURL url = GetURLForPath(kDomain, "/index.html"); + ui_test_utils::NavigateToURL(browser(), url); + + // Enable image labels. + browser()->profile()->GetPrefs()->SetBoolean( + prefs::kAccessibilityImageLabelsEnabled, true); + + // Initially there should be no accessibility mode set. + ASSERT_EQ(1, browser()->tab_strip_model()->count()); + content::WebContents* const web_contents = + browser()->tab_strip_model()->GetWebContentsAt(0); + ASSERT_EQ(ui::AXMode(), web_contents->GetAccessibilityMode()); + + // Enable automation. + base::FilePath extension_path = + test_data_dir_.AppendASCII("automation/tests/basic"); + ExtensionTestMessageListener got_tree(kGotTree, false /* no reply */); + LoadExtension(extension_path); + ASSERT_TRUE(got_tree.WaitUntilSatisfied()); + + // Now the AXMode should include kLabelImages. + ui::AXMode expected_mode = ui::kAXModeWebContentsOnly; + expected_mode.set_mode(ui::AXMode::kLabelImages, true); + EXPECT_EQ(expected_mode, web_contents->GetAccessibilityMode()); +} + IN_PROC_BROWSER_TEST_F(AutomationApiTest, GetTreeByTabId) { StartEmbeddedTestServer(); ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "tab_id.html"))
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc index 1f8be3c..0556e1d3 100644 --- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc +++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -6,9 +6,12 @@ #include "base/bind.h" #include "base/logging.h" +#include "base/task/post_task.h" #include "chrome/browser/extensions/api/image_writer_private/error_messages.h" #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/api/file_handlers/app_file_handler_util.h" @@ -37,6 +40,13 @@ } bool ImageWriterPrivateWriteFromUrlFunction::RunAsync() { +#if defined(OS_CHROMEOS) + if (GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled) || + GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageReadOnly)) { + error_ = image_writer::error::kDeviceWriteError; + return false; + } +#endif std::unique_ptr<image_writer_api::WriteFromUrl::Params> params( image_writer_api::WriteFromUrl::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); @@ -69,6 +79,13 @@ } bool ImageWriterPrivateWriteFromFileFunction::RunAsync() { +#if defined(OS_CHROMEOS) + if (GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled) || + GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageReadOnly)) { + error_ = image_writer::error::kDeviceWriteError; + return false; + } +#endif std::string filesystem_name; std::string filesystem_path; std::string storage_unit_id; @@ -117,6 +134,14 @@ } bool ImageWriterPrivateDestroyPartitionsFunction::RunAsync() { +#if defined(OS_CHROMEOS) + if (GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled) || + GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageReadOnly)) { + error_ = image_writer::error::kDeviceWriteError; + return false; + } + +#endif std::unique_ptr<image_writer_api::DestroyPartitions::Params> params( image_writer_api::DestroyPartitions::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); @@ -138,6 +163,13 @@ } bool ImageWriterPrivateListRemovableStorageDevicesFunction::RunAsync() { +#if defined(OS_CHROMEOS) + if (GetProfile()->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) { + // Return an empty device list. + OnDeviceListReady(base::MakeRefCounted<StorageDeviceList>()); + return true; + } +#endif RemovableStorageProvider::GetAllDevices(base::BindOnce( &ImageWriterPrivateListRemovableStorageDevicesFunction::OnDeviceListReady, this));
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api_unittest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api_unittest.cc new file mode 100644 index 0000000..c248936 --- /dev/null +++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api_unittest.cc
@@ -0,0 +1,70 @@ +// Copyright 2019 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/bind.h" +#include "base/strings/pattern.h" +#include "build/build_config.h" +#include "chrome/browser/extensions/api/image_writer_private/error_messages.h" +#include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" +#include "chrome/browser/extensions/api/image_writer_private/test_utils.h" +#include "chrome/browser/extensions/extension_api_unittest.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/common/extensions/api/image_writer_private.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "extensions/browser/api/file_system/file_system_api.h" +#include "extensions/browser/api_unittest.h" + +namespace extensions { +#if defined(OS_CHROMEOS) +using api::image_writer_private::RemovableStorageDevice; +class ImageWriterPrivateApiUnittest : public ExtensionApiUnittest { + public: + ImageWriterPrivateApiUnittest() {} + + void SetUp() override { + ExtensionApiUnittest::SetUp(); + auto device_list = base::MakeRefCounted<StorageDeviceList>(); + RemovableStorageDevice expected; + expected.vendor = "Vendor 1"; + expected.model = "Model 1"; + expected.capacity = image_writer::kTestFileSize; + expected.removable = true; + device_list->data.push_back(std::move(expected)); + RemovableStorageProvider::SetDeviceListForTesting(device_list); + } + + void TearDown() override { + RemovableStorageProvider::ClearDeviceListForTesting(); + ExtensionApiUnittest::TearDown(); + } +}; + +TEST_F(ImageWriterPrivateApiUnittest, + TestStorageDisabledPolicyReturnsEmptyList) { + PrefService* prefs = profile()->GetPrefs(); + prefs->SetBoolean(prefs::kExternalStorageDisabled, true); + auto function = base::MakeRefCounted< + ImageWriterPrivateListRemovableStorageDevicesFunction>(); + std::unique_ptr<base::ListValue> devices = + RunFunctionAndReturnList(function.get(), "[]"); + ASSERT_TRUE(devices.get() ? devices.get()->empty() : false) + << "Under policy ListDevices should return an empty list."; +} + +TEST_F(ImageWriterPrivateApiUnittest, + TestExternalStorageReadOnlyPolicyFailsWrite) { + PrefService* prefs = profile()->GetPrefs(); + prefs->SetBoolean(prefs::kExternalStorageDisabled, false); + prefs->SetBoolean(prefs::kExternalStorageReadOnly, true); + auto function = + base::MakeRefCounted<ImageWriterPrivateWriteFromFileFunction>(); + ASSERT_TRUE( + base::MatchPattern(RunFunctionAndReturnError(function.get(), "[]"), + image_writer::error::kDeviceWriteError)); +} + +#endif // if defined(OS_CHROMEOS) + +} // namespace extensions \ No newline at end of file
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc index be98e09..cbf553d 100644 --- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc +++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
@@ -3,18 +3,23 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/strings/pattern.h" #include "build/build_config.h" -#include "chrome/browser/extensions/api/image_writer_private/operation.h" +#include "chrome/browser/extensions/api/image_writer_private/error_messages.h" #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" #include "chrome/browser/extensions/api/image_writer_private/test_utils.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/common/extensions/api/image_writer_private.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/file_system/file_system_api.h" - +#include "extensions/browser/api_unittest.h" namespace extensions { using api::image_writer_private::RemovableStorageDevice; +using extension_function_test_utils::RunFunctionAndReturnError; using extensions::image_writer::FakeImageWriterClient; class ImageWriterPrivateApiTest : public ExtensionApiTest { @@ -101,5 +106,4 @@ ASSERT_TRUE(RunPlatformAppTest("image_writer_private/write_from_file")) << message_; } - } // namespace extensions
diff --git a/chrome/browser/extensions/bookmark_app_extension_util.cc b/chrome/browser/extensions/bookmark_app_extension_util.cc index dbb6d114..5675c05 100644 --- a/chrome/browser/extensions/bookmark_app_extension_util.cc +++ b/chrome/browser/extensions/bookmark_app_extension_util.cc
@@ -8,11 +8,13 @@ #include "base/callback.h" #include "build/build_config.h" +#include "chrome/browser/extensions/launch_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" +#include "extensions/browser/extension_prefs.h" #include "extensions/common/extension.h" #if defined(OS_MACOSX) @@ -78,7 +80,16 @@ #endif // defined(OS_CHROMEOS) } -bool CanBookmarkAppReparentTab(bool shortcut_created) { +bool CanBookmarkAppReparentTab(Profile* profile, + const Extension* extension, + bool shortcut_created) { + // Reparent the web contents into its own window only if that is the + // extension's launch type. + if (!extension || + extensions::GetLaunchType(extensions::ExtensionPrefs::Get(profile), + extension) != extensions::LAUNCH_TYPE_WINDOW) { + return false; + } #if defined(OS_MACOSX) // On macOS it is only possible to reparent the window when the shortcut (app // shim) was created. See https://crbug.com/915571.
diff --git a/chrome/browser/extensions/bookmark_app_extension_util.h b/chrome/browser/extensions/bookmark_app_extension_util.h index f332c08c..fcde5da8 100644 --- a/chrome/browser/extensions/bookmark_app_extension_util.h +++ b/chrome/browser/extensions/bookmark_app_extension_util.h
@@ -26,7 +26,9 @@ bool CanBookmarkAppBePinnedToShelf(); void BookmarkAppPinToShelf(const Extension* extension); -bool CanBookmarkAppReparentTab(bool shortcut_created); +bool CanBookmarkAppReparentTab(Profile* profile, + const Extension* extension, + bool shortcut_created); void BookmarkAppReparentTab(content::WebContents* contents, const Extension* extension);
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc index bdab6320..6db1194 100644 --- a/chrome/browser/extensions/bookmark_app_helper.cc +++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -490,12 +490,14 @@ BookmarkAppPinToShelf(extension); // If there is a browser, it means that the app is being installed in the - // foreground: window reparenting needed. + // foreground. const bool reparent_tab = (chrome::FindBrowserWithWebContents(contents_) != nullptr); + // TODO(loyso): Reparenting must be implemented in // chrome/browser/ui/web_applications/ UI layer as a post-install step. - if (reparent_tab && CanBookmarkAppReparentTab(shortcut_created)) { + if (reparent_tab && + CanBookmarkAppReparentTab(profile_, extension, shortcut_created)) { DCHECK(!profile_->IsOffTheRecord()); BookmarkAppReparentTab(contents_, extension); if (CanBookmarkAppRevealAppShim())
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc index aaae659..e9a5ef1 100644 --- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc +++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -42,6 +42,8 @@ {"chrome_app/chrome_app_icon_32.png", IDR_CHROME_APP_ICON_32}, {"chrome_app/chrome_app_icon_192.png", IDR_CHROME_APP_ICON_192}, {"pdf/ink/ink_lib_binary.js", IDR_INK_LIB_BINARY_JS}, + {"pdf/ink/pthread-main.js", IDR_INK_PTHREAD_MAIN_JS}, + {"pdf/ink/glcore_base.js.mem", IDR_INK_GLCORE_BASE_JS_MEM, true}, {"pdf/ink/glcore_base.wasm", IDR_INK_GLCORE_BASE_WASM, true}, {"pdf/ink/glcore_wasm_bootstrap_compiled.js", IDR_INK_GLCORE_WASM_BOOTSTRAP_COMPILED_JS},
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc index 659f17f..51e835b 100644 --- a/chrome/browser/extensions/chrome_url_request_util.cc +++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -239,10 +239,6 @@ void OnMimeTypeRead(scoped_refptr<base::RefCountedMemory> data, std::string* read_mime_type, bool read_result) { - if (!read_result) { - client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); - return; - } network::ResourceResponseHead head; head.request_start = base::TimeTicks::Now(); head.response_start = base::TimeTicks::Now();
diff --git a/chrome/browser/extensions/service_worker_messaging_apitest.cc b/chrome/browser/extensions/service_worker_messaging_apitest.cc index a6ce1a08..e7571b75 100644 --- a/chrome/browser/extensions/service_worker_messaging_apitest.cc +++ b/chrome/browser/extensions/service_worker_messaging_apitest.cc
@@ -105,6 +105,14 @@ EXPECT_TRUE(reply_listener.WaitUntilSatisfied()); } +// Tests chrome.tabs.sendMessage from SW extension to content script. +IN_PROC_BROWSER_TEST_P(ServiceWorkerMessagingTest, WorkerToTab) { + ASSERT_TRUE(StartEmbeddedTestServer()); + ASSERT_TRUE( + RunExtensionTest("service_worker/messaging/send_message_worker_to_tab")) + << message_; +} + INSTANTIATE_TEST_SUITE_P(ServiceWorkerMessagingTestWithNativeBindings, ServiceWorkerMessagingTest, ::testing::Values(NATIVE_BINDINGS));
diff --git a/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc b/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc index 01a71bf..b35cbe66 100644 --- a/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc +++ b/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc
@@ -97,8 +97,8 @@ // Owned by its native widget. Will be destroyed when its widget is destroyed. incognito_promo_ = FeaturePromoBubbleView::CreateOwned( app_menu_button, views::BubbleBorder::TOP_RIGHT, - GetPromoStringSpecifier(), - FeaturePromoBubbleView::ActivationAction::ACTIVATE); + FeaturePromoBubbleView::ActivationAction::ACTIVATE, + GetPromoStringSpecifier()); views::Widget* widget = incognito_promo_->GetWidget(); incognito_promo_observer_.Add(widget); app_menu_button->SetPromoFeature(InProductHelpFeature::kIncognitoWindow);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2654ceb..93375091 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -247,11 +247,6 @@ "expiry_milestone": 76 }, { - "name": "autofill-preview-style", - "owners": [ "ftirelo" ], - "expiry_milestone": 73 - }, - { "name": "autofill-profile-client-validation", "owners": [ "parastoog" ], "expiry_milestone": 77 @@ -378,7 +373,7 @@ }, { "name": "composited-layer-borders", - // "owners": [ "your-team" ], + "owners": [ "ccameron" ], "expiry_milestone": 76 }, { @@ -651,7 +646,7 @@ }, { "name": "disallow-unsafe-http-downloads", - // "owners": [ "your-team" ], + "owners": [ "cthomp" ], "expiry_milestone": 76 }, { @@ -838,6 +833,11 @@ "expiry_milestone": 76 }, { + "name": "enable-autofill-do-not-upload-save-unsupported-cards", + "owners": [ "annelim@google.com", "jsaul@google.com" ], + "expiry_milestone": 76 + }, + { "name": "enable-autofill-import-non-focusable-credit-card-forms", "owners": [ "hozhng@google.com", "jiahuiguo@google.com" ], "expiry_milestone": 76 @@ -953,11 +953,6 @@ "expiry_milestone": 76 }, { - "name": "enable-chromevox-developer-option", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-client-lo-fi", "owners": [ "//components/data_reduction_proxy/OWNERS" ], "expiry_milestone": 76 @@ -1178,11 +1173,6 @@ "expiry_milestone": 76 }, { - "name": "enable-gesture-navigation", - "owners": [ "jinsukkim@chromium.org" ], - "expiry_milestone": 76 - }, - { "name": "enable-google-branded-context-menu", "owners": [ "edwardjung@chromium.org" ], "expiry_milestone": 76 @@ -1222,11 +1212,6 @@ "expiry_milestone": 76 }, { - "name": "enable-home-launcher", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-homepage-tile", "owners": [ "dimich", "twellington" ], "expiry_milestone": 78 @@ -1408,8 +1393,8 @@ }, { "name": "enable-notification-indicator", - // "owners": [ "your-team" ], - "expiry_milestone": 76 + "owners": [ "newcomer" ], + "expiry_milestone": 78 }, { "name": "enable-ntlm-v2", @@ -1452,11 +1437,6 @@ "expiry_milestone": 76 }, { - "name": "enable-nup-printing", - "owners": [ "skau" ], - "expiry_milestone": 76 - }, - { "name": "enable-offer-store-unmasked-wallet-cards", // "owners": [ "your-team" ], "expiry_milestone": 76 @@ -1542,11 +1522,6 @@ "expiry_milestone": 76 }, { - "name": "enable-policy-tool", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-previews-android-omnibox-ui", "owners": [ "//components/data_reduction_proxy/OWNERS" ], "expiry_milestone": 76 @@ -1638,12 +1613,6 @@ "expiry_milestone": 76 }, { - "name": "enable-service-worker-servicification", - "owners": [ "worker-dev@chromium.org" ], - // Enabled by default in M72. - "expiry_milestone": 73 - }, - { "name": "enable-shill-sandboxing", // "owners": [ "your-team" ], "expiry_milestone": 76 @@ -1665,6 +1634,11 @@ "expiry_milestone": 76 }, { + "name": "enable-site-isolation-for-password-sites", + "owners": [ "site-isolation-dev", "alexmos", "lukasza" ], + "expiry_milestone": 77 + }, + { "name": "enable-site-per-process", "owners": [ "site-isolation-dev", "creis", "lukasza" ], // Even after shipping some form of Site Isolation on Android, we want to @@ -1743,11 +1717,6 @@ "expiry_milestone": 76 }, { - "name": "enable-sync-pseudo-uss-passwords", - "owners": [ "mastiz", "//components/sync/OWNERS" ], - "expiry_milestone": 76 - }, - { "name": "enable-sync-pseudo-uss-preferences", "owners": [ "mastiz", "//components/sync/OWNERS" ], "expiry_milestone": 76 @@ -2226,6 +2195,11 @@ "expiry_milestone": 76 }, { + "name": "link-managed-notice-to-management-page", + "owners": [ "chrome-enterprise-team-core@google.com" ], + "expiry_milestone": 76 + }, + { "name": "list-all-display-modes", "owners": [ "//ui/display/OWNERS" ], // This flag is used for debugging and development purposes to list all @@ -2234,8 +2208,12 @@ }, { "name": "load-media-router-component-extension", - // "owners": [ "your-team" ], - "expiry_milestone": 76 + "owners": [ "mfoltz", "media-dev" ], + // This flag has two purposes: in-team development/Q&A, and allowing + // Chromium users to load this extension, which isn't normally distributed + // with Chromium. It can be removed once the extension is removed, which has + // external dependencies. + "expiry_milestone": -1 }, { "name": "lsd-permission-prompt", @@ -2296,7 +2274,16 @@ "expiry_milestone": -1 }, { - "name": "memlog-sampling", + "name": "memlog-in-process", + "owners": [ "erikchen", "ssid", "etienneb", "alph" ], + // Memlog is Chrome's heap profiler. It is used for both automated and + // manual performance analysis. This flag allows a user or developer to + // capture a memlog without disturbing the situation under test by + // restarting to apply a switch. It should not be removed. + "expiry_milestone": -1 + }, + { + "name": "memlog-sampling-rate", "owners": [ "erikchen", "ssid", "etienneb", "alph" ], // Memlog is Chrome's heap profiler. It is used for both automated and // manual performance analysis. This flag allows a user or developer to @@ -2384,11 +2371,6 @@ "expiry_milestone": 76 }, { - "name": "offline-bookmarks", - "owners": [ "jianli", "offline-dev" ], - "expiry_milestone": 76 - }, - { "name": "offline-indicator-always-http-probe", "owners": [ "jianli", "offline-dev" ], "expiry_milestone": 76 @@ -2885,13 +2867,8 @@ "expiry_milestone": 76 }, { - "name": "slide-top-chrome-with-page-scrolls", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "smart-text-selection", - // "owners": [ "your-team" ], + "owners": [ "djacobo", "linben" ], "expiry_milestone": 76 }, { @@ -2935,11 +2912,6 @@ "expiry_milestone": 76 }, { - "name": "sync-standalone-transport", - "owners": [ "treib", "//components/sync/OWNERS" ], - "expiry_milestone": 76 - }, - { "name": "sync-support-secondary-account", "owners": [ "treib", "//components/sync/OWNERS" ], "expiry_milestone": 76 @@ -3032,7 +3004,7 @@ }, { "name": "ui-show-composited-layer-borders", - // "owners": [ "your-team" ], + "owners": [ "ccameron" ], "expiry_milestone": 76 }, {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 678e3ed1..d41d125 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -115,7 +115,8 @@ "Allows autofill to fill dynamically changing forms"; const char kAutofillNoLocalSaveOnUploadSuccessName[] = - "Disable locally saving card when credit card upload succeeds"; + "Disable saving local copy of uploaded card when credit card upload " + "succeeds"; const char kAutofillNoLocalSaveOnUploadSuccessDescription[] = "When enabled, no local copy of server card will be saved when credit card " "upload succeeds."; @@ -411,6 +412,12 @@ "offering card upload to Google Payments, the offer-to-save dialog " "displays an expiration date selector."; +const char kEnableAutofillDoNotUploadSaveUnsupportedCardsName[] = + "Prevents upload save on cards from unsupported networks"; +const char kEnableAutofillDoNotUploadSaveUnsupportedCardsDescription[] = + "If enabled, cards from unsupported networks will not be offered upload " + "save, and will instead be offered local save."; + const char kEnableAutofillImportNonFocusableCreditCardFormsName[] = "Allow credit card import from forms that disappear after entry"; const char kEnableAutofillImportNonFocusableCreditCardFormsDescription[] = @@ -756,10 +763,12 @@ "with hit-test data computed from the CompositorFrame."; const char kEnableOutOfProcessHeapProfilingName[] = - "Out of process heap profiling start mode."; + "Chrome heap profiling start mode."; const char kEnableOutOfProcessHeapProfilingDescription[] = - "Creates a profiling service that records stacktraces for all live, " - "malloced objects. Heap dumps can be obtained at chrome://tracing " + "Starts heap profiling service that records sampled memory allocation " + "profile having each sample attributed with a callstack. " + "The sampling resolution is controlled with --memlog-sampling flag. " + "Recorded heap dumps can be obtained at chrome://tracing " "[category:memory-infra] and chrome://memory-internals. This setting " "controls which processes are profiled. As long as this setting is not " "disabled, users can start profiling any given process in " @@ -776,8 +785,14 @@ "Profile a random sampling of renderer processes, ensuring only one is " "ever profiled at a time."; +const char kOutOfProcessHeapProfilingInProcess[] = + "Run the heap profiling service in the browser process."; +const char kOutOfProcessHeapProfilingInProcessDescription[] = + "Makes profiling service (if enabled) to be executed within the browser " + "process. By default the service is run in a dedicated utility process."; + const char kOutOfProcessHeapProfilingKeepSmallAllocations[] = - "Emit small allocations in memlog heap dumps."; + "Emit small allocations in memlog heap dumps (deprecated)."; const char kOutOfProcessHeapProfilingKeepSmallAllocationsDescription[] = "By default, small allocations are pruned from the heap dump. This reduces " "the size of the compressed trace by 100x. If pruning is disabled, the " @@ -787,11 +802,12 @@ "automatically uploaded traces will always be pruned. This only affects " "manually taken memory-infra traces."; -const char kOutOfProcessHeapProfilingSampling[] = "Sample memlog allocations"; -const char kOutOfProcessHeapProfilingSamplingDescription[] = - "Use a poisson process to sample allocations. Defaults to a sample rate of " - "10000. This results in low noise for large and/or frequent allocations [" - "[size * frequency >> 10000]. This means that aggregate numbers [e.g. " +const char kOutOfProcessHeapProfilingSamplingRate[] = + "Sampling interval in bytes for memlog allocations."; +const char kOutOfProcessHeapProfilingSamplingRateDescription[] = + "Use a poisson process to sample allocations. Defaults to a sampling rate " + "of 100KB. This results in low noise for large and/or frequent allocations " + "[size * frequency >> 100KB]. This means that aggregate numbers [e.g. " "total size of malloc-ed objects] and large and/or frequent allocations " "can be trusted with high fidelity."; @@ -2632,6 +2648,12 @@ const char kSiteExplorationUiDescription[] = "Show site suggestions in the Exploration UI"; +const char kSiteIsolationForPasswordSitesName[] = + "Site Isolation For Password Sites"; +const char kSiteIsolationForPasswordSitesDescription[] = + "Security mode that enables site isolation for sites based on " + "password-oriented heuristics, such as a user typing in a password."; + const char kStrictSiteIsolationName[] = "Strict site isolation"; const char kStrictSiteIsolationDescription[] = "Security mode that enables site isolation for all sites (SitePerProcess). " @@ -2758,6 +2780,12 @@ const char kHappinessTrackingSurveysForDesktopDescription[] = "Enable showing Happiness Tracking Surveys to users on Desktop"; +const char kLinkManagedNoticeToChromeUIManagementURLName[] = + "Link managed notice to the management page"; +const char kLinkManagedNoticeToChromeUIManagementURLDescription[] = + "Makes the managed notice 'Managed by your organization' a link to " + "chrome://management"; + const char kOmniboxDriveSuggestionsName[] = "Omnibox Google Drive Document suggestions"; const char kOmniboxDriveSuggestionsDescriptions[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 1dff92a13..9128e079 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -278,6 +278,9 @@ extern const char kEnableAutofillCreditCardUploadEditableExpirationDateDescription[]; +extern const char kEnableAutofillDoNotUploadSaveUnsupportedCardsName[]; +extern const char kEnableAutofillDoNotUploadSaveUnsupportedCardsDescription[]; + extern const char kEnableAutofillImportNonFocusableCreditCardFormsName[]; extern const char kEnableAutofillImportNonFocusableCreditCardFormsDescription[]; @@ -471,8 +474,10 @@ extern const char kEnableOutOfProcessHeapProfilingModeRendererSampling[]; extern const char kOutOfProcessHeapProfilingKeepSmallAllocations[]; extern const char kOutOfProcessHeapProfilingKeepSmallAllocationsDescription[]; -extern const char kOutOfProcessHeapProfilingSampling[]; -extern const char kOutOfProcessHeapProfilingSamplingDescription[]; +extern const char kOutOfProcessHeapProfilingInProcess[]; +extern const char kOutOfProcessHeapProfilingInProcessDescription[]; +extern const char kOutOfProcessHeapProfilingSamplingRate[]; +extern const char kOutOfProcessHeapProfilingSamplingRateDescription[]; extern const char kOOPHPStackModeName[]; extern const char kOOPHPStackModeDescription[]; @@ -1548,6 +1553,9 @@ extern const char kSiteExplorationUiName[]; extern const char kSiteExplorationUiDescription[]; +extern const char kSiteIsolationForPasswordSitesName[]; +extern const char kSiteIsolationForPasswordSitesDescription[]; + extern const char kSpannableInlineAutocompleteName[]; extern const char kSpannableInlineAutocompleteDescription[]; @@ -1621,6 +1629,9 @@ extern const char kHappinessTrackingSurveysForDesktopName[]; extern const char kHappinessTrackingSurveysForDesktopDescription[]; +extern const char kLinkManagedNoticeToChromeUIManagementURLName[]; +extern const char kLinkManagedNoticeToChromeUIManagementURLDescription[]; + extern const char kOmniboxDriveSuggestionsName[]; extern const char kOmniboxDriveSuggestionsDescriptions[];
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc index 7b6cf39..5b7214b 100644 --- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc +++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -103,91 +103,26 @@ return page->GetTypeForTesting(); } -// Sets the absolute Site Engagement |score| for the testing origin. -void SetEngagementScore(Browser* browser, const GURL& url, double score) { - SiteEngagementService::Get(browser->profile()) - ->ResetBaseScoreForURL(url, score); -} - -bool IsUrlShowing(Browser* browser) { - return !browser->location_bar_model()->GetFormattedFullURL().empty(); -} - -// Simulates a link click navigation. We don't use -// ui_test_utils::NavigateToURL(const GURL&) because it simulates the user -// typing the URL, causing the site to have a site engagement score of at -// least LOW. -void NavigateToURL(Browser* browser, const GURL& url) { - NavigateParams params(browser, url, ui::PAGE_TRANSITION_LINK); - params.initiator_origin = url::Origin::Create(GURL("about:blank")); - params.disposition = WindowOpenDisposition::CURRENT_TAB; - params.is_renderer_initiated = true; - ui_test_utils::NavigateToURL(¶ms); -} - -// Same as NavigateToUrl, but wait for the load to complete before returning. -void NavigateToURLSync(Browser* browser, const GURL& url) { - content::TestNavigationObserver navigation_observer( - browser->tab_strip_model()->GetActiveWebContents(), 1); - NavigateToURL(browser, url); - navigation_observer.Wait(); -} - -// Load given URL and verify that it loaded an interstitial and hid the URL. -void LoadAndCheckInterstitialAt(Browser* browser, const GURL& url) { - content::WebContents* web_contents = - browser->tab_strip_model()->GetActiveWebContents(); - - EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); - - NavigateToURLSync(browser, url); - EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, - GetInterstitialType(web_contents)); - EXPECT_FALSE(IsUrlShowing(browser)); -} - void SendInterstitialCommand(content::WebContents* web_contents, SecurityInterstitialCommand command) { GetCurrentInterstitial(web_contents) ->CommandReceived(base::NumberToString(command)); } -void SendInterstitialCommandSync(Browser* browser, - SecurityInterstitialCommand command) { - content::WebContents* web_contents = - browser->tab_strip_model()->GetActiveWebContents(); - - EXPECT_TRUE(GetCurrentInterstitial(web_contents)); - - content::TestNavigationObserver navigation_observer(web_contents, 1); - SendInterstitialCommand(web_contents, command); - navigation_observer.Wait(); - - EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); - EXPECT_TRUE(IsUrlShowing(browser)); -} - -// Verify that no interstitial is shown, regardless of feature state. -void TestInterstitialNotShown(Browser* browser, const GURL& navigated_url) { - content::WebContents* web_contents = - browser->tab_strip_model()->GetActiveWebContents(); - - NavigateToURLSync(browser, navigated_url); - EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); - - // Navigate to an empty page. This will happen after any - // LookalikeUrlService tasks, so will effectively wait for those tasks to - // finish. - NavigateToURLSync(browser, GURL("about:blank")); - EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); -} - } // namespace class LookalikeUrlNavigationThrottleBrowserTest : public InProcessBrowserTest, public testing::WithParamInterface<UIEnabled> { protected: + // Sets the absolute Site Engagement |score| for the testing origin. + static void SetEngagementScore(Browser* browser, + const GURL& url, + double score) { + SiteEngagementService::Get(browser->profile()) + ->ResetBaseScoreForURL(url, score); + } + void SetUp() override { if (ui_enabled()) { feature_list_.InitAndEnableFeature( @@ -250,9 +185,50 @@ test_ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName).empty()); } + void TestInterstitialNotShown(Browser* browser, const GURL& navigated_url) { + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, navigated_url); + navigation_observer.Wait(); + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_TRUE(IsUrlShowing(browser)); + } + { + // Navigate to an empty page. This will happen after any + // LookalikeUrlService tasks, so will effectively wait for those tasks to + // finish. + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, GURL("about:blank")); + navigation_observer.Wait(); + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_TRUE(IsUrlShowing(browser)); + } + } + + // Tests only that the interstitial is shown (when enabled) when the user + // tries to visit the provided URL. + void TestOnlyInterstitialShown(Browser* browser, const GURL& navigated_url) { + if (!ui_enabled()) { + return; + } + + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, navigated_url); + navigation_observer.Wait(); + + EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, + GetInterstitialType(web_contents)); + EXPECT_FALSE(IsUrlShowing(browser)); + } + // Tests that the histogram event |expected_event| is recorded. If the UI is - // enabled, additional events for interstitial display and link click will - // also be tested. + // enabled, additinal events for interstitial display and link click will also + // be tested. void TestHistogramEventsRecordedAndInterstitialShown( Browser* browser, base::HistogramTester* histograms, @@ -260,46 +236,31 @@ const GURL& expected_suggested_url, LookalikeUrlNavigationThrottle::NavigationSuggestionEvent expected_event) { - if (!ui_enabled()) { - TestInterstitialNotShown(browser, navigated_url); + if (ui_enabled()) { + // If the feature is enabled, the UI will be displayed. + TestInterstitialShown(browser, navigated_url, expected_suggested_url); histograms->ExpectTotalCount( LookalikeUrlNavigationThrottle::kHistogramName, 1); histograms->ExpectBucketCount( LookalikeUrlNavigationThrottle::kHistogramName, expected_event, 1); + histograms->ExpectTotalCount(kInterstitialDecisionMetric, 2); + histograms->ExpectBucketCount(kInterstitialDecisionMetric, + MetricsHelper::SHOW, 1); + histograms->ExpectBucketCount(kInterstitialDecisionMetric, + MetricsHelper::DONT_PROCEED, 1); + + histograms->ExpectTotalCount(kInterstitialInteractionMetric, 1); + histograms->ExpectBucketCount(kInterstitialInteractionMetric, + MetricsHelper::TOTAL_VISITS, 1); return; } - history::HistoryService* const history_service = - HistoryServiceFactory::GetForProfile( - browser->profile(), ServiceAccessType::EXPLICIT_ACCESS); - ui_test_utils::WaitForHistoryToLoad(history_service); - - LoadAndCheckInterstitialAt(browser, navigated_url); - SendInterstitialCommandSync(browser, - SecurityInterstitialCommand::CMD_DONT_PROCEED); - EXPECT_EQ(expected_suggested_url, - browser->tab_strip_model()->GetActiveWebContents()->GetURL()); - - // Clicking the link in the interstitial should also remove the original - // URL from history. - ui_test_utils::HistoryEnumerator enumerator(browser->profile()); - EXPECT_FALSE(base::ContainsValue(enumerator.urls(), navigated_url)); - + TestInterstitialNotShown(browser, navigated_url); histograms->ExpectTotalCount(LookalikeUrlNavigationThrottle::kHistogramName, 1); histograms->ExpectBucketCount( LookalikeUrlNavigationThrottle::kHistogramName, expected_event, 1); - - histograms->ExpectTotalCount(kInterstitialDecisionMetric, 2); - histograms->ExpectBucketCount(kInterstitialDecisionMetric, - MetricsHelper::SHOW, 1); - histograms->ExpectBucketCount(kInterstitialDecisionMetric, - MetricsHelper::DONT_PROCEED, 1); - - histograms->ExpectTotalCount(kInterstitialInteractionMetric, 1); - histograms->ExpectBucketCount(kInterstitialInteractionMetric, - MetricsHelper::TOTAL_VISITS, 1); } // Tests that the histogram event |expected_event| is recorded. If the UI is @@ -311,59 +272,146 @@ const GURL& navigated_url, LookalikeUrlNavigationThrottle::NavigationSuggestionEvent expected_event) { - if (!ui_enabled()) { - TestInterstitialNotShown(browser, navigated_url); + if (ui_enabled()) { + // If the feature is enabled, the UI will be displayed. + DisplayThenIgnoreInterstitial(browser, navigated_url); histograms->ExpectTotalCount( LookalikeUrlNavigationThrottle::kHistogramName, 1); histograms->ExpectBucketCount( LookalikeUrlNavigationThrottle::kHistogramName, expected_event, 1); + histograms->ExpectTotalCount(kInterstitialDecisionMetric, 2); + histograms->ExpectBucketCount(kInterstitialDecisionMetric, + MetricsHelper::SHOW, 1); + histograms->ExpectBucketCount(kInterstitialDecisionMetric, + MetricsHelper::PROCEED, 1); + + histograms->ExpectTotalCount(kInterstitialInteractionMetric, 1); + histograms->ExpectBucketCount(kInterstitialInteractionMetric, + MetricsHelper::TOTAL_VISITS, 1); + + TestInterstitialNotShown(browser, navigated_url); + return; } - history::HistoryService* const history_service = - HistoryServiceFactory::GetForProfile( - browser->profile(), ServiceAccessType::EXPLICIT_ACCESS); - ui_test_utils::WaitForHistoryToLoad(history_service); - - LoadAndCheckInterstitialAt(browser, navigated_url); - - // Clicking the ignore button in the interstitial should remove the - // interstitial and navigate to the original URL. - SendInterstitialCommandSync(browser, - SecurityInterstitialCommand::CMD_PROCEED); - EXPECT_EQ(navigated_url, - browser->tab_strip_model()->GetActiveWebContents()->GetURL()); - - // Clicking the link should cause the original URL to appear in history. - ui_test_utils::HistoryEnumerator enumerator(browser->profile()); - EXPECT_TRUE(base::ContainsValue(enumerator.urls(), navigated_url)); - + TestInterstitialNotShown(browser, navigated_url); histograms->ExpectTotalCount(LookalikeUrlNavigationThrottle::kHistogramName, 1); histograms->ExpectBucketCount( LookalikeUrlNavigationThrottle::kHistogramName, expected_event, 1); - - histograms->ExpectTotalCount(kInterstitialDecisionMetric, 2); - histograms->ExpectBucketCount(kInterstitialDecisionMetric, - MetricsHelper::SHOW, 1); - histograms->ExpectBucketCount(kInterstitialDecisionMetric, - MetricsHelper::PROCEED, 1); - - histograms->ExpectTotalCount(kInterstitialInteractionMetric, 1); - histograms->ExpectBucketCount(kInterstitialInteractionMetric, - MetricsHelper::TOTAL_VISITS, 1); - - TestInterstitialNotShown(browser, navigated_url); } ukm::TestUkmRecorder* test_ukm_recorder() { return test_ukm_recorder_.get(); } base::SimpleTestClock* test_clock() { return &test_clock_; } + protected: virtual bool ui_enabled() const { return GetParam() == UIEnabled::kEnabled; } - private: + static bool IsUrlShowing(Browser* browser) { + return !browser->location_bar_model()->GetFormattedFullURL().empty(); + } + + // Simulates a link click navigation. We don't use + // ui_test_utils::NavigateToURL(const GURL&) because it simulates the user + // typing the URL, causing the site to have a site engagement score of at + // least LOW. + static void NavigateToURL(Browser* browser, const GURL& url) { + NavigateParams params(browser, url, ui::PAGE_TRANSITION_LINK); + params.initiator_origin = url::Origin::Create(GURL("about:blank")); + params.disposition = WindowOpenDisposition::CURRENT_TAB; + params.is_renderer_initiated = true; + ui_test_utils::NavigateToURL(¶ms); + } + + // Checks that navigating to |navigated_url| results in displaying an + // interstitial suggesting navigation to |expected_suggestion_url|. + // Both |navigated_url| and |expected_suggested_url| can be ASCII or IDN. + static void TestInterstitialShown(Browser* browser, + const GURL& navigated_url, + const GURL& expected_suggested_url) { + history::HistoryService* const history_service = + HistoryServiceFactory::GetForProfile( + browser->profile(), ServiceAccessType::EXPLICIT_ACCESS); + ui_test_utils::WaitForHistoryToLoad(history_service); + + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_TRUE(IsUrlShowing(browser)); + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, navigated_url); + navigation_observer.Wait(); + } + + EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, + GetInterstitialType(web_contents)); + EXPECT_FALSE(IsUrlShowing(browser)); + + // Clicking the link in the interstitial should remove the interstitial and + // navigate to the suggested URL. + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + SendInterstitialCommand(web_contents, + SecurityInterstitialCommand::CMD_DONT_PROCEED); + navigation_observer.Wait(); + } + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_EQ(expected_suggested_url, web_contents->GetURL()); + EXPECT_TRUE(IsUrlShowing(browser)); + + // Clicking the link in the interstitial should also remove the original URL + // from history. + ui_test_utils::HistoryEnumerator enumerator(browser->profile()); + EXPECT_FALSE(base::ContainsValue(enumerator.urls(), navigated_url)); + } + + // Checks that navigating to |navigated_url| results in displaying an + // interstitial, that, when ignored, proceeds to |navigated_url|. + // |navigated_url| can be ASCII or IDN. + static void DisplayThenIgnoreInterstitial(Browser* browser, + const GURL& navigated_url) { + history::HistoryService* const history_service = + HistoryServiceFactory::GetForProfile( + browser->profile(), ServiceAccessType::EXPLICIT_ACCESS); + ui_test_utils::WaitForHistoryToLoad(history_service); + + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, navigated_url); + navigation_observer.Wait(); + } + + EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, + GetInterstitialType(web_contents)); + EXPECT_FALSE(IsUrlShowing(browser)); + + // Clicking the ignore button in the interstitial should remove the + // interstitial and navigate to the original URL. + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + SendInterstitialCommand(web_contents, + SecurityInterstitialCommand::CMD_PROCEED); + navigation_observer.Wait(); + } + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_EQ(navigated_url, web_contents->GetURL()); + EXPECT_TRUE(IsUrlShowing(browser)); + + // Clicking the link should result in the original URL appearing in history. + ui_test_utils::HistoryEnumerator enumerator(browser->profile()); + EXPECT_TRUE(base::ContainsValue(enumerator.urls(), navigated_url)); + } + base::test::ScopedFeatureList feature_list_; std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; base::SimpleTestClock test_clock_; @@ -371,6 +419,64 @@ class LookalikeUrlInterstitialPageBrowserTest : public LookalikeUrlNavigationThrottleBrowserTest { + public: + // Checks that navigating to |navigated_url| displays an interstitial with a + // hidden URL, and then navigating to other pages shows/hides the URLs + // appropriately both when a URL is expected to be hidden (by navigating to + // "chrome://newtab") and when expected to be shown (by navigating to + // |subsequent_url|). + static void TestInterstitialHidesUrlThenRestores(Browser* browser, + const GURL& navigated_url, + const GURL& subsequent_url) { + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_TRUE(IsUrlShowing(browser)); + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser, navigated_url); + navigation_observer.Wait(); + } + + EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, + GetInterstitialType(web_contents)); + EXPECT_FALSE(IsUrlShowing(browser)); + + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + ui_test_utils::NavigateToURL(browser, subsequent_url); + navigation_observer.Wait(); + } + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + EXPECT_TRUE(IsUrlShowing(browser)); + + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + ui_test_utils::NavigateToURL(browser, GURL("chrome://newtab")); + navigation_observer.Wait(); + } + + EXPECT_FALSE(IsUrlShowing(browser)); + } + + // Load the given URL and verify that it loaded an interstitial. + void LoadInterstitialAt(const GURL& navigated_url) { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + EXPECT_EQ(nullptr, GetCurrentInterstitial(web_contents)); + { + content::TestNavigationObserver navigation_observer(web_contents, 1); + NavigateToURL(browser(), navigated_url); + navigation_observer.Wait(); + } + + EXPECT_EQ(LookalikeUrlInterstitialPage::kTypeForTesting, + GetInterstitialType(web_contents)); + } + protected: bool ui_enabled() const override { return true; } }; @@ -682,28 +788,23 @@ CheckUkm({kNavigatedUrl}, "MatchType", MatchType::kEditDistance); } -// Navigate to lookalike domains that redirect to benign domains and ensure that -// we display an interstitial along the way. -IN_PROC_BROWSER_TEST_F(LookalikeUrlInterstitialPageBrowserTest, +// Navigate to lookalike domains that redirect to benign domains. Ensure that +// we display an interstitial along the way if configured via a feature param. +IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationThrottleBrowserTest, Interstitial_CapturesRedirects) { { // Verify it works when the lookalike domain is the first in the chain const GURL kNavigatedUrl = GetLongRedirect("goooglé.com", "example.net", "example.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - LoadAndCheckInterstitialAt(browser(), kNavigatedUrl); + TestOnlyInterstitialShown(browser(), kNavigatedUrl); } - - // LoadAndCheckInterstitialAt assumes there's not an interstitial already - // showing (since otherwise it can't be sure that the navigation caused it). - NavigateToURLSync(browser(), GetURL("example.com")); - { // ...or when it's later in the chain const GURL kNavigatedUrl = GetLongRedirect("example.net", "goooglé.com", "example.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - LoadAndCheckInterstitialAt(browser(), kNavigatedUrl); + TestOnlyInterstitialShown(browser(), kNavigatedUrl); } } @@ -716,7 +817,9 @@ return; const GURL navigated_url = GetURL("goooglé.com"); + TestInterstitialNotShown(browser(), navigated_url); + CheckUkm({navigated_url}, "UserAction", UserAction::kInterstitialNotShown); } @@ -727,8 +830,14 @@ const GURL navigated_url = GetURL("goooglé.com"); const GURL subsequent_url = GetURL("example.com"); - LoadAndCheckInterstitialAt(browser(), navigated_url); - NavigateToURLSync(browser(), subsequent_url); + LoadInterstitialAt(navigated_url); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver navigation_observer(web_contents, 1); + ui_test_utils::NavigateToURL(browser(), subsequent_url); + navigation_observer.Wait(); + CheckUkm({navigated_url}, "UserAction", UserAction::kCloseOrBack); } @@ -738,9 +847,15 @@ UkmRecordedAfterSuggestionAccepted) { const GURL navigated_url = GetURL("goooglé.com"); - LoadAndCheckInterstitialAt(browser(), navigated_url); - SendInterstitialCommandSync(browser(), - SecurityInterstitialCommand::CMD_DONT_PROCEED); + LoadInterstitialAt(navigated_url); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver navigation_observer(web_contents, 1); + SendInterstitialCommand(web_contents, + SecurityInterstitialCommand::CMD_DONT_PROCEED); + navigation_observer.Wait(); + CheckUkm({navigated_url}, "UserAction", UserAction::kAcceptSuggestion); } @@ -750,58 +865,23 @@ UkmRecordedAfterSuggestionIgnored) { const GURL navigated_url = GetURL("goooglé.com"); - LoadAndCheckInterstitialAt(browser(), navigated_url); - SendInterstitialCommandSync(browser(), - SecurityInterstitialCommand::CMD_PROCEED); + LoadInterstitialAt(navigated_url); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver navigation_observer(web_contents, 1); + SendInterstitialCommand(web_contents, + SecurityInterstitialCommand::CMD_PROCEED); + navigation_observer.Wait(); + CheckUkm({navigated_url}, "UserAction", UserAction::kClickThrough); } // Verify that the URL shows normally on pages after a lookalike interstitial. IN_PROC_BROWSER_TEST_F(LookalikeUrlInterstitialPageBrowserTest, UrlShownAfterInterstitial) { - LoadAndCheckInterstitialAt(browser(), GetURL("goooglé.com")); - - // URL should be showing again when we navigate to a normal URL - NavigateToURLSync(browser(), GetURL("example.com")); - EXPECT_TRUE(IsUrlShowing(browser())); - - // URL should still get hidden when we navigate to a page with a hidden URL. - NavigateToURLSync(browser(), GURL("chrome://newtab")); - EXPECT_FALSE(IsUrlShowing(browser())); -} - -// Verify that bypassing warnings in the main profile does not affect incognito. -IN_PROC_BROWSER_TEST_F(LookalikeUrlInterstitialPageBrowserTest, - MainProfileDoesNotAffectIncognito) { - const GURL kNavigatedUrl = GetURL("googlé.com"); - - // Set low engagement scores in the main profile and in incognito. - Browser* incognito = CreateIncognitoBrowser(); - SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - SetEngagementScore(incognito, kNavigatedUrl, kLowEngagement); - - LoadAndCheckInterstitialAt(browser(), kNavigatedUrl); - // PROCEEDing will disable the interstitial on subsequent navigations - SendInterstitialCommandSync(browser(), - SecurityInterstitialCommand::CMD_PROCEED); - - LoadAndCheckInterstitialAt(incognito, kNavigatedUrl); -} - -// Verify that bypassing warnings in incognito does not affect the main profile. -IN_PROC_BROWSER_TEST_F(LookalikeUrlInterstitialPageBrowserTest, - IncognitoDoesNotAffectMainProfile) { - const GURL kNavigatedUrl = GetURL("googlé.com"); - - // Set low engagement scores in the main profile and in incognito. - Browser* incognito = CreateIncognitoBrowser(); - SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - SetEngagementScore(incognito, kNavigatedUrl, kLowEngagement); - - LoadAndCheckInterstitialAt(incognito, kNavigatedUrl); - // PROCEEDing will disable the interstitial on subsequent navigations - SendInterstitialCommandSync(incognito, - SecurityInterstitialCommand::CMD_PROCEED); - - LoadAndCheckInterstitialAt(browser(), kNavigatedUrl); + const GURL kNavigatedUrl = GetURL("goooglé.com"); + const GURL kSubsequentUrl = GetURL("example.com"); + TestInterstitialHidesUrlThenRestores(browser(), kNavigatedUrl, + kSubsequentUrl); }
diff --git a/chrome/browser/media/media_engagement_score.cc b/chrome/browser/media/media_engagement_score.cc index bdda9b1..9a32200 100644 --- a/chrome/browser/media/media_engagement_score.cc +++ b/chrome/browser/media/media_engagement_score.cc
@@ -57,6 +57,13 @@ return std::make_unique<base::DictionaryValue>(); } +void GetIntegerFromScore(base::DictionaryValue* dict, + base::StringPiece key, + int* out) { + if (base::Value* v = dict->FindKeyOfType(key, base::Value::Type::INTEGER)) + *out = v->GetInt(); +} + } // namespace // static. @@ -101,21 +108,31 @@ if (!score_dict_) return; - score_dict_->GetInteger(kVisitsKey, &visits_); - score_dict_->GetInteger(kMediaPlaybacksKey, &media_playbacks_); - score_dict_->GetBoolean(kHasHighScoreKey, &is_high_); - score_dict_->GetInteger(kAudiblePlaybacksKey, &audible_playbacks_); - score_dict_->GetInteger(kSignificantPlaybacksKey, &significant_playbacks_); - score_dict_->GetInteger(kVisitsWithMediaTagKey, &visits_with_media_tag_); - score_dict_->GetInteger(kHighScoreChanges, &high_score_changes_); - score_dict_->GetInteger(kSignificantMediaPlaybacksKey, - &media_element_playbacks_); - score_dict_->GetInteger(kSignificantAudioContextPlaybacksKey, - &audio_context_playbacks_); + GetIntegerFromScore(score_dict_.get(), kVisitsKey, &visits_); + GetIntegerFromScore(score_dict_.get(), kMediaPlaybacksKey, &media_playbacks_); + GetIntegerFromScore(score_dict_.get(), kAudiblePlaybacksKey, + &audible_playbacks_); + GetIntegerFromScore(score_dict_.get(), kSignificantPlaybacksKey, + &significant_playbacks_); + GetIntegerFromScore(score_dict_.get(), kVisitsWithMediaTagKey, + &visits_with_media_tag_); + GetIntegerFromScore(score_dict_.get(), kHighScoreChanges, + &high_score_changes_); + GetIntegerFromScore(score_dict_.get(), kSignificantMediaPlaybacksKey, + &media_element_playbacks_); + GetIntegerFromScore(score_dict_.get(), kSignificantAudioContextPlaybacksKey, + &audio_context_playbacks_); - double internal_time; - if (score_dict_->GetDouble(kLastMediaPlaybackTimeKey, &internal_time)) - last_media_playback_time_ = base::Time::FromInternalValue(internal_time); + if (base::Value* value = score_dict_->FindKeyOfType( + kHasHighScoreKey, base::Value::Type::BOOLEAN)) { + is_high_ = value->GetBool(); + } + + if (base::Value* value = score_dict_->FindKeyOfType( + kLastMediaPlaybackTimeKey, base::Value::Type::DOUBLE)) { + last_media_playback_time_ = + base::Time::FromInternalValue(value->GetDouble()); + } // Recalculate the total score and high bit. If the high bit changed we // should commit this. This should only happen if we change the threshold @@ -184,21 +201,34 @@ int stored_media_element_playbacks = 0; int stored_audio_context_playbacks = 0; - score_dict_->GetInteger(kVisitsKey, &stored_visits); - score_dict_->GetInteger(kMediaPlaybacksKey, &stored_media_playbacks); - score_dict_->GetDouble(kLastMediaPlaybackTimeKey, - &stored_last_media_playback_internal); - score_dict_->GetBoolean(kHasHighScoreKey, &is_high); - score_dict_->GetInteger(kAudiblePlaybacksKey, &stored_audible_playbacks); - score_dict_->GetInteger(kSignificantPlaybacksKey, - &stored_significant_playbacks); - score_dict_->GetInteger(kVisitsWithMediaTagKey, - &stored_visits_with_media_tag); - score_dict_->GetInteger(kHighScoreChanges, &high_score_changes); - score_dict_->GetInteger(kSignificantMediaPlaybacksKey, - &stored_media_element_playbacks); - score_dict_->GetInteger(kSignificantAudioContextPlaybacksKey, - &stored_audio_context_playbacks); + if (!score_dict_) + return false; + + if (base::Value* value = score_dict_->FindKeyOfType( + kHasHighScoreKey, base::Value::Type::BOOLEAN)) { + is_high = value->GetBool(); + } + + if (base::Value* value = score_dict_->FindKeyOfType( + kLastMediaPlaybackTimeKey, base::Value::Type::DOUBLE)) { + stored_last_media_playback_internal = value->GetDouble(); + } + + GetIntegerFromScore(score_dict_.get(), kVisitsKey, &stored_visits); + GetIntegerFromScore(score_dict_.get(), kMediaPlaybacksKey, + &stored_media_playbacks); + GetIntegerFromScore(score_dict_.get(), kAudiblePlaybacksKey, + &stored_audible_playbacks); + GetIntegerFromScore(score_dict_.get(), kSignificantPlaybacksKey, + &stored_significant_playbacks); + GetIntegerFromScore(score_dict_.get(), kVisitsWithMediaTagKey, + &stored_visits_with_media_tag); + GetIntegerFromScore(score_dict_.get(), kHighScoreChanges, + &high_score_changes); + GetIntegerFromScore(score_dict_.get(), kSignificantMediaPlaybacksKey, + &stored_media_element_playbacks); + GetIntegerFromScore(score_dict_.get(), kSignificantAudioContextPlaybacksKey, + &stored_audio_context_playbacks); bool changed = stored_visits != visits() || stored_media_playbacks != media_playbacks() ||
diff --git a/chrome/browser/offline_pages/android/offline_page_model_factory.cc b/chrome/browser/offline_pages/android/offline_page_model_factory.cc index 3096336..5a43cba 100644 --- a/chrome/browser/offline_pages/android/offline_page_model_factory.cc +++ b/chrome/browser/offline_pages/android/offline_page_model_factory.cc
@@ -65,7 +65,7 @@ std::unique_ptr<ArchiveManager> archive_manager(new DownloadArchiveManager( temporary_archives_dir, persistent_archives_dir, DownloadPrefs::GetDefaultDownloadDirectory(), background_task_runner, - profile)); + profile->GetPrefs())); auto clock = std::make_unique<base::DefaultClock>(); std::unique_ptr<SystemDownloadManager> download_manager(
diff --git a/chrome/browser/offline_pages/download_archive_manager.cc b/chrome/browser/offline_pages/download_archive_manager.cc index ea0e22e2..5e939c2d9 100644 --- a/chrome/browser/offline_pages/download_archive_manager.cc +++ b/chrome/browser/offline_pages/download_archive_manager.cc
@@ -5,7 +5,6 @@ #include <string> #include "chrome/browser/offline_pages/download_archive_manager.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" @@ -16,20 +15,20 @@ const base::FilePath& private_archives_dir, const base::FilePath& public_archives_dir, const scoped_refptr<base::SequencedTaskRunner>& task_runner, - Profile* profile) + PrefService* prefs) : ArchiveManager(temporary_archives_dir, private_archives_dir, public_archives_dir, task_runner), - profile_(profile) {} + prefs_(prefs) {} DownloadArchiveManager::~DownloadArchiveManager() {} const base::FilePath& DownloadArchiveManager::GetPublicArchivesDir() { - if (profile_) { + if (prefs_) { // Use the preference set by the download location dialog, if present. std::string directory_preference = - profile_->GetPrefs()->GetString(prefs::kDownloadDefaultDirectory); + prefs_->GetString(prefs::kDownloadDefaultDirectory); if (!directory_preference.empty()) { download_archives_dir_ = base::FilePath(directory_preference); // Must set the member variable so the reference will outlive the
diff --git a/chrome/browser/offline_pages/download_archive_manager.h b/chrome/browser/offline_pages/download_archive_manager.h index 868d493..92fe23f 100644 --- a/chrome/browser/offline_pages/download_archive_manager.h +++ b/chrome/browser/offline_pages/download_archive_manager.h
@@ -10,7 +10,7 @@ #include "base/memory/ref_counted.h" #include "components/offline_pages/core/archive_manager.h" -class Profile; +class PrefService; namespace base { class SequencedTaskRunner; @@ -27,13 +27,13 @@ const base::FilePath& private_archives_dir, const base::FilePath& public_archives_dir, const scoped_refptr<base::SequencedTaskRunner>& task_runner, - Profile* profile); + PrefService* prefs); ~DownloadArchiveManager() override; const base::FilePath& GetPublicArchivesDir() override; private: - Profile* profile_; + PrefService* prefs_; base::FilePath download_archives_dir_; DISALLOW_COPY_AND_ASSIGN(DownloadArchiveManager);
diff --git a/chrome/browser/offline_pages/download_archive_manager_unittest.cc b/chrome/browser/offline_pages/download_archive_manager_unittest.cc index 6b7ca69..8528bd4 100644 --- a/chrome/browser/offline_pages/download_archive_manager_unittest.cc +++ b/chrome/browser/offline_pages/download_archive_manager_unittest.cc
@@ -5,9 +5,10 @@ #include "chrome/browser/offline_pages/download_archive_manager.h" #include "base/macros.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/download/download_prefs.h" #include "chrome/common/pref_names.h" -#include "chrome/test/base/testing_profile.h" -#include "components/prefs/pref_service.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -30,26 +31,26 @@ void TearDown() override; void PumpLoop(); - TestingProfile* profile() { return &profile_; } + sync_preferences::TestingPrefServiceSyncable* prefs() { return &prefs_; } DownloadArchiveManager* archive_manager() { return archive_manager_.get(); } private: content::TestBrowserThreadBundle browser_thread_bundle_; - TestingProfile profile_; + sync_preferences::TestingPrefServiceSyncable prefs_; std::unique_ptr<DownloadArchiveManager> archive_manager_; DISALLOW_COPY_AND_ASSIGN(DownloadArchiveManagerTest); }; void DownloadArchiveManagerTest::SetUp() { // Set up preferences to point to kChromePublicSdCardDir. - profile()->GetPrefs()->SetString(prefs::kDownloadDefaultDirectory, - kChromePublicSdCardDir); + DownloadPrefs::RegisterProfilePrefs(prefs()->registry()); + prefs()->SetString(prefs::kDownloadDefaultDirectory, kChromePublicSdCardDir); // Create a DownloadArchiveManager to use. archive_manager_.reset(new DownloadArchiveManager( base::FilePath(kTemporaryDir), base::FilePath(kPrivateDir), base::FilePath(kPublicDir), base::ThreadTaskRunnerHandle::Get(), - profile())); + prefs())); } void DownloadArchiveManagerTest::TearDown() { @@ -61,7 +62,7 @@ ASSERT_EQ(kChromePublicSdCardDir, download_dir.AsUTF8Unsafe()); } -TEST_F(DownloadArchiveManagerTest, NullProfile) { +TEST_F(DownloadArchiveManagerTest, NullPrefs) { DownloadArchiveManager download_archive_manager( base::FilePath(kTemporaryDir), base::FilePath(kPrivateDir), base::FilePath(kPublicDir), base::ThreadTaskRunnerHandle::Get(), nullptr);
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.cc b/chrome/browser/offline_pages/offline_page_request_handler.cc index 4bb0f68..4daa8e8 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler.cc
@@ -618,7 +618,7 @@ // after intermediate redirects for authentication. Previously this case was // not handled and some pages might be saved with same URLs. Though we fixed // the problem, we still need to support those pages already saved with this - if (url_ == GetCurrentOfflinePage().original_url && + if (url_ == GetCurrentOfflinePage().original_url_if_different && url_ != GetCurrentOfflinePage().url) { ReportRequestResult(RequestResult::REDIRECTED, network_state_); Redirect(GetCurrentOfflinePage().url);
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc index 6f912794..77fb6dc 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -1835,7 +1835,7 @@ // Check if the original URL is still present. OfflinePageItem page = this->GetPage(offline_id); - EXPECT_EQ(kUrl, page.original_url); + EXPECT_EQ(kUrl, page.original_url_if_different); // No redirect should be triggered when original URL is same as final URL. this->LoadPage(kUrl);
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc index c50a94fd..a8d3df3 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -204,7 +204,8 @@ // ad, even if it navigates to a non-ad page. This function labels all of a // page's frames, even those that fail to commit. void AdsPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) { + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { FrameTreeNodeId frame_tree_node_id = navigation_handle->GetFrameTreeNodeId(); bool is_adframe = DetectAds(navigation_handle);
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h index c427898..ff5f1ce 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -58,7 +58,8 @@ void ReadyToCommitNextNavigation( content::NavigationHandle* navigation_handle) override; void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) override; + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; void OnDidInternalNavigationAbort( content::NavigationHandle* navigation_handle) override; ObservePolicy FlushMetricsOnAppEnterBackground(
diff --git a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc index a276f66d..a1b70bad 100644 --- a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc
@@ -170,7 +170,8 @@ } void AMPPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) { + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { if (!navigation_handle->HasCommitted()) return;
diff --git a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.h index 30d28cf8..35b984e 100644 --- a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.h
@@ -68,7 +68,8 @@ void OnCommitSameDocumentNavigation( content::NavigationHandle* navigation_handle) override; void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) override; + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo&) override; void OnFrameDeleted(content::RenderFrameHost* rfh) override; void OnDomContentLoadedEventStart( const page_load_metrics::mojom::PageLoadTiming& timing,
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc index e044b9d..2e95332 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -11,6 +11,7 @@ #include "base/metrics/histogram_macros.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h" #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" #include "content/public/common/process_type.h" #include "net/http/http_response_headers.h" @@ -96,6 +97,12 @@ "PageLoad.Experimental.PaintTiming.NavigationToLargestContentPaint"; const char kHistogramLargestContentPaintContentType[] = "PageLoad.Experimental.PaintTiming.LargestContentPaint.ContentType"; +const char kHistogramLargestContentPaintAllFrames[] = + "PageLoad.Experimental.PaintTiming.NavigationToLargestContentPaint." + "AllFrames"; +const char kHistogramLargestContentPaintAllFramesContentType[] = + "PageLoad.Experimental.PaintTiming.LargestContentPaint.AllFrames." + "ContentType"; const char kHistogramTimeToInteractive[] = "PageLoad.Experimental.NavigationToInteractive"; const char kHistogramInteractiveToInteractiveDetection[] = @@ -269,7 +276,8 @@ cache_bytes_(0), network_bytes_(0), network_bytes_including_headers_(0), - redirect_chain_size_(0) {} + redirect_chain_size_(0), + largest_contentful_paint_handler_() {} CorePageLoadMetricsObserver::~CorePageLoadMetricsObserver() {} @@ -785,6 +793,17 @@ largest_content_type); } + const page_load_metrics::TimingInfo& paint = + largest_contentful_paint_handler_.MergeMainFrameAndSubframes(); + if (!paint.IsEmpty() && + WasStartedInForegroundOptionalEventInForeground(paint.Time(), info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentPaintAllFrames, + paint.Time().value()); + UMA_HISTOGRAM_ENUMERATION( + internal::kHistogramLargestContentPaintAllFramesContentType, + paint.Type()); + } + if (timing.paint_timing->first_paint && !timing.paint_timing->first_meaningful_paint) { RecordFirstMeaningfulPaintStatus( @@ -909,3 +928,18 @@ PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramTotalCompletedResources, num_cache_resources_ + num_network_resources_); } + +void CorePageLoadMetricsObserver::OnTimingUpdate( + content::RenderFrameHost* subframe_rfh, + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& extra_info) { + largest_contentful_paint_handler_.RecordTiming(timing.paint_timing, + subframe_rfh); +} + +void CorePageLoadMetricsObserver::OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { + largest_contentful_paint_handler_.OnDidFinishSubFrameNavigation( + navigation_handle, extra_info); +}
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h index d490998c..bdb6a4b 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_ #define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_ +#include "chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "services/metrics/public/cpp/ukm_source.h" @@ -31,6 +32,8 @@ extern const char kHistogramLastTextPaint[]; extern const char kHistogramLargestContentPaint[]; extern const char kHistogramLargestContentPaintContentType[]; +extern const char kHistogramLargestContentPaintAllFrames[]; +extern const char kHistogramLargestContentPaintAllFramesContentType[]; extern const char kHistogramTimeToInteractive[]; extern const char kHistogramParseDuration[]; extern const char kHistogramParseBlockedOnScriptLoad[]; @@ -220,6 +223,15 @@ const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& resources) override; + void OnTimingUpdate( + content::RenderFrameHost* subframe_rfh, + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; + + void OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; + private: void RecordTimingHistograms( const page_load_metrics::mojom::PageLoadTiming& timing, @@ -260,6 +272,9 @@ base::TimeTicks first_paint_; + page_load_metrics::LargestContentfulPaintHandler + largest_contentful_paint_handler_; + DISALLOW_COPY_AND_ASSIGN(CorePageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc index 9ddf11b..0440fc2 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -40,6 +40,7 @@ void SetUp() override { page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp(); + page_load_metrics::LargestContentfulPaintHandler::SetTestMode(true); } }; @@ -614,8 +615,8 @@ SimulateTimingUpdate(timing); NavigateAndCommit(GURL(kDefaultTestUrl2)); - histogram_tester().ExpectTotalCount( - internal::kHistogramFirstMeaningfulPaint, 1); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstMeaningfulPaint, + 1); histogram_tester().ExpectTotalCount( internal::kHistogramParseStartToFirstMeaningfulPaint, 1); histogram_tester().ExpectBucketCount( @@ -630,6 +631,7 @@ // Pick a value that lines up with a histogram bucket. timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_image_paint_size = 10u; PopulateRequiredTimingFields(&timing); NavigateAndCommit(GURL(kDefaultTestUrl)); @@ -642,25 +644,23 @@ testing::ElementsAre(base::Bucket(4780, 1))); } -TEST_F(CorePageLoadMetricsObserverTest, LargestImagePaintIgnoreSubFrame) { +TEST_F(CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_OnlySubframeProvided) { const char kSubframeTestUrl[] = "https://google.com/subframe.html"; - // Create a main frame timing with a largest_image_paint that happens late. page_load_metrics::mojom::PageLoadTiming timing; page_load_metrics::InitPageLoadTimingForTest(&timing); - timing.navigation_start = base::Time::FromDoubleT(1); - // Pick a value that lines up with a histogram bucket. - timing.paint_timing->largest_image_paint = - base::TimeDelta::FromMilliseconds(4780); + timing.navigation_start = base::Time::FromDoubleT(100); + // Intentionally not set candidates for the main frame. PopulateRequiredTimingFields(&timing); - // Create a subframe timing with a largest_image_paint that happens before the - // largest_image_paint in the main frame timing. + // Create a subframe timing with a largest_image_paint. page_load_metrics::mojom::PageLoadTiming subframe_timing; page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); - subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.navigation_start = base::Time::FromDoubleT(200); subframe_timing.paint_timing->largest_image_paint = - base::TimeDelta::FromMilliseconds(0); + base::TimeDelta::FromMilliseconds(4780); + subframe_timing.paint_timing->largest_image_paint_size = 100u; PopulateRequiredTimingFields(&subframe_timing); // Commit the main frame and a subframe. @@ -678,10 +678,270 @@ // Navigate again to force histogram recording in the main frame. NavigateAndCommit(GURL(kDefaultTestUrl2)); - // Ensure that the largest_image_paint timing for the main frame is recorded. + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(4780, 1))); EXPECT_THAT( - histogram_tester().GetAllSamples(internal::kHistogramLargestImagePaint), - testing::ElementsAre(base::Bucket(4780, 1))); + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kImage), + 1))); +} + +TEST_F(CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_OnlyMainFrameProvided) { + const char kSubframeTestUrl[] = "https://google.com/subframe.html"; + + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + // Pick a value that lines up with a histogram bucket. + timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_image_paint_size = 50u; + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + // Intentionally not set candidates for the subframes. + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kDefaultTestUrl)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Navigate again to force histogram recording in the main frame. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(4780, 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kImage), + 1))); +} + +// This is to test whether LargestContentfulPaintAllFrames could merge +// candidates from different frames correctly. The merging will substitutes the +// existing candidate if a larger candidate from subframe is provided. +TEST_F(CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_MergeFromFramesBySize_SubframeLarger) { + const char kSubframeTestUrl[] = "https://google.com/subframe.html"; + + // Create a main frame timing with a largest_image_paint that happens late. + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + // Pick a value that lines up with a histogram bucket. + timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(10000); + timing.paint_timing->largest_image_paint_size = 50u; + PopulateRequiredTimingFields(&timing); + + // Create a candidate in subframe with a larger size. + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + subframe_timing.paint_timing->largest_image_paint_size = 100u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kDefaultTestUrl)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Navigate again to force histogram recording in the main frame. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(4780, 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kImage), + 1))); +} + +// This is to test whether LargestContentfulPaintAllFrames could merge +// candidates from different frames correctly. The merging will substitutes the +// existing candidate if a larger candidate from main frame is provided. +TEST_F(CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_MergeFromFramesBySize_MainFrameLarger) { + const char kSubframeTestUrl[] = "https://google.com/subframe.html"; + + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + // Pick a value that lines up with a histogram bucket. + timing.paint_timing->largest_text_paint = + base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_text_paint_size = 100u; + PopulateRequiredTimingFields(&timing); + + // Create a candidate in subframe with a smaller size. + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.paint_timing->largest_text_paint = + base::TimeDelta::FromMilliseconds(300); + subframe_timing.paint_timing->largest_text_paint_size = 50u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kDefaultTestUrl)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Navigate again to force histogram recording in the main frame. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(4780, 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kText), + 1))); +} + +// This tests a trade-off we have made - aggregating all subframe candidates, +// which makes LCP unable to substitute the subframe candidate with a smaller +// candidate. This test provides two subframe candidates, the later larger than +// the first one. +TEST_F(CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_SubframesCandidateOnlyGetLarger_Larger) { + const char kSubframeTestUrl[] = "https://google.com/subframe.html"; + + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + subframe_timing.paint_timing->largest_image_paint_size = 50u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kDefaultTestUrl)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(300); + subframe_timing.paint_timing->largest_image_paint_size = 10u; + SimulateTimingUpdate(subframe_timing, subframe); + + // Navigate again to force histogram recording in the main frame. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + // Ensure that the largest_image_paint timing for the main frame is recorded. + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(4780, 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kImage), + 1))); +} + +// This tests a trade-off we have made - aggregating all subframe candidates, +// which makes LCP unable to substitute the subframe candidate with a smaller +// candidate. This test provides two subframe candidates, the later smaller than +// the first one. +TEST_F( + CorePageLoadMetricsObserverTest, + LargestContentfulPaintAllFrames_SubframesCandidateOnlyGetLarger_Smaller) { + const char kSubframeTestUrl[] = "https://google.com/subframe.html"; + + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + subframe_timing.paint_timing->largest_image_paint_size = 10u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kDefaultTestUrl)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(990); + subframe_timing.paint_timing->largest_image_paint_size = 50u; + SimulateTimingUpdate(subframe_timing, subframe); + + // Navigate again to force histogram recording in the main frame. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + // Ensure that the largest_image_paint timing for the main frame is recorded. + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFrames), + testing::ElementsAre(base::Bucket(990, 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + internal::kHistogramLargestContentPaintAllFramesContentType), + testing::ElementsAre(base::Bucket( + static_cast<base::HistogramBase::Sample>(LargestContentType::kImage), + 1))); } TEST_F(CorePageLoadMetricsObserverTest, @@ -710,11 +970,13 @@ timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(1000); + timing.paint_timing->largest_image_paint_size = 10u; PopulateRequiredTimingFields(&timing); SimulateTimingUpdate(timing); timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_image_paint_size = 5u; PopulateRequiredTimingFields(&timing); SimulateTimingUpdate(timing); // Navigate again to force histogram recording. @@ -815,6 +1077,7 @@ // Pick a value that lines up with a histogram bucket. timing.paint_timing->largest_text_paint = base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_text_paint_size = 10u; PopulateRequiredTimingFields(&timing); NavigateAndCommit(GURL(kDefaultTestUrl)); @@ -850,11 +1113,9 @@ page_load_metrics::mojom::PageLoadTiming timing; page_load_metrics::InitPageLoadTimingForTest(&timing); timing.navigation_start = base::Time::FromDoubleT(1); - // When either the time and size is 0, they are not set and should be excluded - // from recording to UMA. We are using the size as the condition of exclusion. - timing.paint_timing->largest_text_paint = - base::TimeDelta::FromMilliseconds(4780); - timing.paint_timing->largest_text_paint_size = 0; + // When the size is 0, the timing is regarded as not set and should be + // excluded from recording to UMA. + timing.paint_timing->largest_text_paint_size = 0u; PopulateRequiredTimingFields(&timing); NavigateAndCommit(GURL(kDefaultTestUrl));
diff --git a/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.cc b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.cc new file mode 100644 index 0000000..38664672 --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.cc
@@ -0,0 +1,178 @@ +// Copyright 2019 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/page_load_metrics/observers/largest_contentful_paint_handler.h" +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" +#include "content/public/browser/render_frame_host.h" + +namespace page_load_metrics { + +// TODO(crbug/616901): True in test only. Since we are unable to config +// navigation start in tests, we disable the offsetting to make the test +// deterministic. +static bool g_disable_subframe_navigation_start_offset = false; + +namespace { + +const TimingInfo& MergeTimingsBySizeAndTime(const TimingInfo& timing1, + const TimingInfo& timing2) { + // When both are empty, just return either. + if (timing1.IsEmpty() && timing2.IsEmpty()) + return timing1; + + if (timing1.IsEmpty() && !timing2.IsEmpty()) + return timing2; + if (!timing1.IsEmpty() && timing2.IsEmpty()) + return timing1; + if (timing1.Size() > timing2.Size()) + return timing1; + if (timing1.Size() < timing2.Size()) + return timing2; + // When both sizes are equal + DCHECK(timing1.Time()); + DCHECK(timing2.Time()); + if (timing1.Time().value() < timing2.Time().value()) + return timing1; + return timing2; +} + +void MergeForSubframesWithAdjustedTime( + TimingInfo* inout_timing, + const base::Optional<base::TimeDelta>& candidate_new_time, + const uint64_t& candidate_new_size) { + DCHECK(inout_timing); + const TimingInfo new_candidate(candidate_new_time, candidate_new_size, + inout_timing->Type()); + const TimingInfo& merged_candidate = + MergeTimingsBySizeAndTime(new_candidate, *inout_timing); + inout_timing->Reset(merged_candidate.Time(), merged_candidate.Size()); +} + +void MergeForSubframes( + TimingInfo* inout_timing, + const base::Optional<base::TimeDelta>& candidate_new_time, + const uint64_t& candidate_new_size, + base::TimeDelta navigation_start_offset) { + MergeForSubframesWithAdjustedTime( + inout_timing, + candidate_new_time ? navigation_start_offset + candidate_new_time.value() + : candidate_new_time, + candidate_new_size); +} + +bool IsSubframe(content::RenderFrameHost* subframe_rfh) { + return subframe_rfh != nullptr && subframe_rfh->GetParent() != nullptr; +} + +} // namespace + +TimingInfo::TimingInfo(PageLoadMetricsObserver::LargestContentType type) + : time_(base::Optional<base::TimeDelta>()), size_(0), type_(type) {} +TimingInfo::TimingInfo( + const base::Optional<base::TimeDelta>& time, + const uint64_t& size, + const page_load_metrics::PageLoadMetricsObserver::LargestContentType type) + : time_(time), size_(size), type_(type) {} + +TimingInfo::TimingInfo(const TimingInfo& other) = default; + +// static +void LargestContentfulPaintHandler::SetTestMode(bool enabled) { + g_disable_subframe_navigation_start_offset = enabled; +} + +void TimingInfo::Reset(const base::Optional<base::TimeDelta>& time, + const uint64_t& size) { + size_ = size; + time_ = time; + DCHECK(HasConsistentTimeAndSize()); +} + +ContentfulPaint::ContentfulPaint() + : text_(PageLoadMetricsObserver::LargestContentType::kText), + image_(PageLoadMetricsObserver::LargestContentType::kImage) {} + +const TimingInfo& ContentfulPaint::MergeTextAndImageTiming() { + return MergeTimingsBySizeAndTime(text_, image_); +} + +LargestContentfulPaintHandler::LargestContentfulPaintHandler() = default; +LargestContentfulPaintHandler::~LargestContentfulPaintHandler() = default; + +void LargestContentfulPaintHandler::RecordTiming( + const mojom::PaintTimingPtr& timing, + content::RenderFrameHost* subframe_rfh) { + if (!IsSubframe(subframe_rfh)) { + RecordMainFrameTiming(timing); + return; + } + // For subframes + base::TimeDelta navigation_start_offset; + if (!g_disable_subframe_navigation_start_offset) { + const auto it = subframe_navigation_start_offset_.find( + subframe_rfh->GetFrameTreeNodeId()); + if (it == subframe_navigation_start_offset_.end()) { + // We received timing information for an untracked load. Ignore it. + return; + } + navigation_start_offset = it->second; + } + RecordSubframeTiming(timing, navigation_start_offset); +} + +const TimingInfo& LargestContentfulPaintHandler::MergeMainFrameAndSubframes() { + const TimingInfo& main_frame_timing = + main_frame_contentful_paint_.MergeTextAndImageTiming(); + const TimingInfo& subframe_timing = + subframe_contentful_paint_.MergeTextAndImageTiming(); + return MergeTimingsBySizeAndTime(main_frame_timing, subframe_timing); +} + +// We handle subframe and main frame differently. For main frame, we directly +// substitute the candidate when we receive a new one. For subframes (plural), +// we merge the candidates from different subframes by keeping the largest one. +// Note that the merging of subframes' timings will make +// |subframe_contentful_paint_| unable to be replaced with a smaller paint (it +// should have been able when a large ephemeral element is removed). This is a +// trade-off we make to keep a simple algorithm, otherwise we will have to +// track one candidate per subframe. +void LargestContentfulPaintHandler::RecordSubframeTiming( + const mojom::PaintTimingPtr& timing, + const base::TimeDelta& navigation_start_offset) { + MergeForSubframes(&subframe_contentful_paint_.Text(), + timing->largest_text_paint, timing->largest_text_paint_size, + navigation_start_offset); + MergeForSubframes(&subframe_contentful_paint_.Image(), + timing->largest_image_paint, + timing->largest_image_paint_size, navigation_start_offset); +} + +void LargestContentfulPaintHandler::RecordMainFrameTiming( + const mojom::PaintTimingPtr& timing) { + main_frame_contentful_paint_.Text().Reset(timing->largest_text_paint, + timing->largest_text_paint_size); + main_frame_contentful_paint_.Image().Reset(timing->largest_image_paint, + timing->largest_image_paint_size); +} + +void LargestContentfulPaintHandler::OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { + if (!navigation_handle->HasCommitted()) + return; + + // We have a new committed navigation, so discard information about the + // previously committed navigation. + subframe_navigation_start_offset_.erase( + navigation_handle->GetFrameTreeNodeId()); + + if (extra_info.navigation_start > navigation_handle->NavigationStart()) + return; + base::TimeDelta navigation_delta = + navigation_handle->NavigationStart() - extra_info.navigation_start; + subframe_navigation_start_offset_.insert(std::make_pair( + navigation_handle->GetFrameTreeNodeId(), navigation_delta)); +} + +} // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h new file mode 100644 index 0000000..184fc2f --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h
@@ -0,0 +1,97 @@ +// Copyright 2019 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_PAGE_LOAD_METRICS_OBSERVERS_LARGEST_CONTENTFUL_PAINT_HANDLER_H_ +#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_LARGEST_CONTENTFUL_PAINT_HANDLER_H_ + +#include <map> + +#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" +#include "chrome/common/page_load_metrics/page_load_timing.h" + +namespace page_load_metrics { + +class TimingInfo { + public: + explicit TimingInfo( + page_load_metrics::PageLoadMetricsObserver::LargestContentType); + explicit TimingInfo( + const base::Optional<base::TimeDelta>&, + const uint64_t& size, + const page_load_metrics::PageLoadMetricsObserver::LargestContentType); + explicit TimingInfo(const TimingInfo& other); + void Reset(const base::Optional<base::TimeDelta>&, const uint64_t& size); + base::Optional<base::TimeDelta> Time() const { + DCHECK(HasConsistentTimeAndSize()); + return time_; + } + uint64_t Size() const { + DCHECK(HasConsistentTimeAndSize()); + return size_; + } + page_load_metrics::PageLoadMetricsObserver::LargestContentType Type() const { + DCHECK(HasConsistentTimeAndSize()); + return type_; + } + bool IsEmpty() const { + DCHECK(HasConsistentTimeAndSize()); + // |size_| will be 0 as well, as checked by the DCHECK. + return !time_; + } + + private: + TimingInfo() = delete; + // This is only for DCHECK. We will never need the inconsistent state. + bool HasConsistentTimeAndSize() const { + return (time_ && size_) || (!time_ && !size_); + } + base::Optional<base::TimeDelta> time_; + uint64_t size_; + page_load_metrics::PageLoadMetricsObserver::LargestContentType type_; +}; + +class ContentfulPaint { + public: + ContentfulPaint(); + TimingInfo& Text() { return text_; } + TimingInfo& Image() { return image_; } + const TimingInfo& MergeTextAndImageTiming(); + + private: + TimingInfo text_; + TimingInfo image_; +}; + +class LargestContentfulPaintHandler { + public: + static void SetTestMode(bool enabled); + LargestContentfulPaintHandler(); + ~LargestContentfulPaintHandler(); + using FrameTreeNodeId = + page_load_metrics::PageLoadMetricsObserver::FrameTreeNodeId; + void RecordTiming(const page_load_metrics::mojom::PaintTimingPtr&, + content::RenderFrameHost* subframe_rfh); + // We merge the candidates from main frame and subframe to get the largest + // candidate across all frames. + const TimingInfo& MergeMainFrameAndSubframes(); + void OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info); + + private: + void RecordSubframeTiming(const mojom::PaintTimingPtr& timing, + const base::TimeDelta& navigation_start_offset); + void RecordMainFrameTiming(const page_load_metrics::mojom::PaintTimingPtr&); + ContentfulPaint main_frame_contentful_paint_; + ContentfulPaint subframe_contentful_paint_; + + // Navigation start offsets for the most recently committed document in each + // frame. + std::map<FrameTreeNodeId, base::TimeDelta> subframe_navigation_start_offset_; + DISALLOW_COPY_AND_ASSIGN(LargestContentfulPaintHandler); +}; + +} // namespace page_load_metrics + +#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_LARGEST_CONTENTFUL_PAINT_HANDLER_H_
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc index 08ea526f..8b833c58 100644 --- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc
@@ -162,7 +162,8 @@ } void PageCappingPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) { + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { // If the page is not paused, there is no need to pause new frames. if (page_capping_state_ != PageCappingState::kPagePaused) return;
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h index 5d07f47..24182de 100644 --- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h
@@ -81,7 +81,8 @@ ObservePolicy OnCommit(content::NavigationHandle* navigation_handle, ukm::SourceId source_id) override; void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) override; + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; void MediaStartedPlaying( const content::WebContentsObserver::MediaPlayerInfo& video_type, content::RenderFrameHost* render_frame_host) override;
diff --git a/chrome/browser/page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.cc index fd890fcf..71975e61 100644 --- a/chrome/browser/page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.cc
@@ -48,13 +48,14 @@ data->set_session_key(info->drp_session_key); data->set_page_id(info->page_id); data->set_effective_connection_type(previews_data->navigation_ect()); + data->set_lite_page_received(info->status == + previews::ServerLitePageStatus::kSuccess); data->set_connection_type(net::NetworkChangeNotifier::GetConnectionType()); data->set_request_url(handle->GetURL()); data->set_black_listed(previews_data->black_listed_for_lite_page()); data->set_used_data_reduction_proxy(true); data->set_client_lofi_requested(false); - data->set_lite_page_received(false); data->set_lofi_policy_received(false); data->set_lofi_received(false); data->set_was_cached_data_reduction_proxy_response(false);
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc index 8707928..a8c61d8 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h" #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" #include "chrome/browser/profiles/profile.h" #include "components/metrics/net/network_metrics_provider.h" @@ -80,7 +81,8 @@ UkmPageLoadMetricsObserver::UkmPageLoadMetricsObserver( network::NetworkQualityTracker* network_quality_tracker) - : network_quality_tracker_(network_quality_tracker) { + : network_quality_tracker_(network_quality_tracker), + largest_contentful_paint_handler_() { DCHECK(network_quality_tracker_); } @@ -286,6 +288,14 @@ builder.SetExperimental_PaintTiming_NavigationToLargestContentPaint( largest_content_paint_time.value().InMilliseconds()); } + const page_load_metrics::TimingInfo& paint = + largest_contentful_paint_handler_.MergeMainFrameAndSubframes(); + if (!paint.IsEmpty() && + WasStartedInForegroundOptionalEventInForeground(paint.Time(), info)) { + builder + .SetExperimental_PaintTiming_NavigationToLargestContentPaintAllFrames( + paint.Time().value().InMilliseconds()); + } if (timing.interactive_timing->interactive) { base::TimeDelta time_to_interactive = timing.interactive_timing->interactive.value(); @@ -510,3 +520,11 @@ return rounded_document_engagement_score; } + +void UkmPageLoadMetricsObserver::OnTimingUpdate( + content::RenderFrameHost* subframe_rfh, + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& extra_info) { + largest_contentful_paint_handler_.RecordTiming(timing.paint_timing, + subframe_rfh); +}
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h index 907ab59..f60950b 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/optional.h" #include "base/time/time.h" +#include "chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "net/http/http_response_info.h" #include "services/metrics/public/cpp/ukm_source.h" @@ -69,6 +70,11 @@ void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& extra_request_complete_info) override; + void OnTimingUpdate( + content::RenderFrameHost* subframe_rfh, + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; + private: // Records page load timing related metrics available in PageLoadTiming, such // as first contentful paint. @@ -138,6 +144,9 @@ // The connection info for the committed URL. base::Optional<net::HttpResponseInfo::ConnectionInfo> connection_info_; + page_load_metrics::LargestContentfulPaintHandler + largest_contentful_paint_handler_; + DISALLOW_COPY_AND_ASSIGN(UkmPageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc index 71926210..7383cb3 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -24,6 +24,9 @@ #include "testing/gmock/include/gmock/gmock.h" #include "third_party/metrics_proto/system_profile.pb.h" +using content::NavigationSimulator; +using content::RenderFrameHost; +using content::RenderFrameHostTester; using testing::AnyNumber; using testing::Mock; using testing::Return; @@ -34,6 +37,7 @@ const char kTestUrl1[] = "https://www.google.com/"; const char kTestUrl2[] = "https://www.example.com/"; +const char kSubframeTestUrl[] = "https://www.google.com/subframe.html"; class MockNetworkQualityProvider : public network::NetworkQualityTracker { public: @@ -56,6 +60,7 @@ void SetUp() override { page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp(); + page_load_metrics::LargestContentfulPaintHandler::SetTestMode(true); EXPECT_CALL(mock_network_quality_provider_, GetEffectiveConnectionType()) .Times(AnyNumber()) @@ -244,6 +249,7 @@ timing.navigation_start = base::Time::FromDoubleT(1); timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(600); + timing.paint_timing->largest_image_paint_size = 50u; PopulateRequiredTimingFields(&timing); NavigateAndCommit(GURL(kTestUrl1)); @@ -366,18 +372,22 @@ timing.paint_timing->last_image_paint = base::TimeDelta::FromMilliseconds(60); timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(60); + timing.paint_timing->largest_image_paint_size = 10u; timing.paint_timing->last_text_paint = base::TimeDelta::FromMilliseconds(60); timing.paint_timing->largest_text_paint = base::TimeDelta::FromMilliseconds(60); + timing.paint_timing->largest_text_paint_size = 10u; SimulateTimingUpdate(timing); timing.paint_timing->last_image_paint = base::TimeDelta::FromMilliseconds(600); timing.paint_timing->largest_image_paint = base::TimeDelta::FromMilliseconds(600); + timing.paint_timing->largest_image_paint_size = 10u; timing.paint_timing->last_text_paint = base::TimeDelta::FromMilliseconds(600); timing.paint_timing->largest_text_paint = base::TimeDelta::FromMilliseconds(600); + timing.paint_timing->largest_text_paint_size = 10u; SimulateTimingUpdate(timing); // Simulate closing the tab. @@ -416,6 +426,7 @@ timing.navigation_start = base::Time::FromDoubleT(1); timing.paint_timing->largest_text_paint = base::TimeDelta::FromMilliseconds(600); + timing.paint_timing->largest_text_paint_size = 50u; PopulateRequiredTimingFields(&timing); NavigateAndCommit(GURL(kTestUrl1)); @@ -537,6 +548,153 @@ } } +TEST_F(UkmPageLoadMetricsObserverTest, + LargestContentPaintAllFrames_OnlySubframe) { + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + subframe_timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + subframe_timing.paint_timing->largest_image_paint_size = 100u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kTestUrl1)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Simulate closing the tab. + DeleteContents(); + + std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries = + test_ukm_recorder().GetMergedEntriesByName(PageLoad::kEntryName); + EXPECT_EQ(1ul, merged_entries.size()); + + for (const auto& kv : merged_entries) { + test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), + GURL(kTestUrl1)); + test_ukm_recorder().ExpectEntryMetric( + kv.second.get(), + PageLoad:: + kExperimental_PaintTiming_NavigationToLargestContentPaintAllFramesName, + 4780); + EXPECT_TRUE(test_ukm_recorder().EntryHasMetric( + kv.second.get(), PageLoad::kPageTiming_ForegroundDurationName)); + } +} + +TEST_F(UkmPageLoadMetricsObserverTest, + LargestContentPaintAllFrames_OnlyMainFrame) { + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_image_paint_size = 100u; + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kTestUrl1)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Simulate closing the tab. + DeleteContents(); + + std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries = + test_ukm_recorder().GetMergedEntriesByName(PageLoad::kEntryName); + EXPECT_EQ(1ul, merged_entries.size()); + + for (const auto& kv : merged_entries) { + test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), + GURL(kTestUrl1)); + test_ukm_recorder().ExpectEntryMetric( + kv.second.get(), + PageLoad:: + kExperimental_PaintTiming_NavigationToLargestContentPaintAllFramesName, + 4780); + EXPECT_TRUE(test_ukm_recorder().EntryHasMetric( + kv.second.get(), PageLoad::kPageTiming_ForegroundDurationName)); + } +} + +// This is to test whether LargestContentPaintAllFrames can merge the candidates +// from different frames correctly. The metric should pick the larger candidate +// during merging. +TEST_F(UkmPageLoadMetricsObserverTest, + LargestContentPaintAllFrames_MergeFrameCandidateBySize) { + page_load_metrics::mojom::PageLoadTiming timing; + page_load_metrics::InitPageLoadTimingForTest(&timing); + timing.navigation_start = base::Time::FromDoubleT(1); + timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(4780); + timing.paint_timing->largest_image_paint_size = 50u; + PopulateRequiredTimingFields(&timing); + + page_load_metrics::mojom::PageLoadTiming subframe_timing; + page_load_metrics::InitPageLoadTimingForTest(&subframe_timing); + subframe_timing.navigation_start = base::Time::FromDoubleT(2); + timing.paint_timing->largest_image_paint = + base::TimeDelta::FromMilliseconds(990); + timing.paint_timing->largest_image_paint_size = 100u; + PopulateRequiredTimingFields(&subframe_timing); + + // Commit the main frame and a subframe. + NavigateAndCommit(GURL(kTestUrl1)); + RenderFrameHost* subframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSubframeTestUrl), + RenderFrameHostTester::For(web_contents()->GetMainFrame()) + ->AppendChild("subframe")); + + // Simulate timing updates in the main frame and the subframe. + SimulateTimingUpdate(timing); + SimulateTimingUpdate(subframe_timing, subframe); + + // Simulate closing the tab. + DeleteContents(); + + std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries = + test_ukm_recorder().GetMergedEntriesByName(PageLoad::kEntryName); + EXPECT_EQ(1ul, merged_entries.size()); + + for (const auto& kv : merged_entries) { + test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), + GURL(kTestUrl1)); + test_ukm_recorder().ExpectEntryMetric( + kv.second.get(), + PageLoad:: + kExperimental_PaintTiming_NavigationToLargestContentPaintAllFramesName, + 990); + EXPECT_TRUE(test_ukm_recorder().EntryHasMetric( + kv.second.get(), PageLoad::kPageTiming_ForegroundDurationName)); + } +} + TEST_F(UkmPageLoadMetricsObserverTest, LastTextPaint) { page_load_metrics::mojom::PageLoadTiming timing; page_load_metrics::InitPageLoadTimingForTest(&timing);
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc index 5407752..90d0e77 100644 --- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc +++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -99,6 +99,7 @@ WebFeature::kV8MediaCapabilities_DecodingInfo_Method, WebFeature::kOpenerNavigationDownloadCrossOrigin, WebFeature::kLinkRelPrerender, + WebFeature::kAdClickNavigation, })); return *opt_in_features; }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h index 86d2b9f..0ecc67b 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -361,7 +361,8 @@ // that |navigation_handle| will be destroyed soon after this call. Don't // hold a reference to it. virtual void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) {} + content::NavigationHandle* navigation_handle, + const PageLoadExtraInfo& extra_info) {} // OnCommitSameDocumentNavigation is triggered when a same-document navigation // commits within the main frame of the current page. Note that
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc index 9943ed9..72342a32 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc
@@ -65,6 +65,11 @@ return observed_page_fields_.IsSet(field); } +bool PageLoadMetricsTestWaiter::DidObserveWebFeature( + blink::mojom::WebFeature feature) const { + return observed_web_features_.test(static_cast<size_t>(feature)); +} + void PageLoadMetricsTestWaiter::Wait() { if (ExpectationsSatisfied()) return; @@ -161,7 +166,8 @@ } void PageLoadMetricsTestWaiter::OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) { + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { if (SubframeNavigationExpectationsSatisfied()) return; @@ -297,9 +303,10 @@ void PageLoadMetricsTestWaiter::WaiterMetricsObserver:: OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) { + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) { if (waiter_) - waiter_->OnDidFinishSubFrameNavigation(navigation_handle); + waiter_->OnDidFinishSubFrameNavigation(navigation_handle, extra_info); } } // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h index 6de54ef..e10595a 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h
@@ -58,6 +58,9 @@ // Whether the given TimingField was observed in the page. bool DidObserveInPage(TimingField field) const; + // Whether the given WebFeature was observed in the page. + bool DidObserveWebFeature(blink::mojom::WebFeature feature) const; + // Waits for PageLoadMetrics events that match the fields set by the add // expectation methods. All matching fields must be set to end this wait. void Wait(); @@ -109,7 +112,8 @@ const page_load_metrics::PageLoadExtraInfo& extra_info) override; void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle) override; + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info) override; private: const base::WeakPtr<PageLoadMetricsTestWaiter> waiter_; @@ -180,7 +184,8 @@ const PageLoadExtraInfo& extra_info); void OnDidFinishSubFrameNavigation( - content::NavigationHandle* navigation_handle); + content::NavigationHandle* navigation_handle, + const page_load_metrics::PageLoadExtraInfo& extra_info); void OnTrackerCreated(page_load_metrics::PageLoadTracker* tracker) override;
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc index a64c199a..45f948a 100644 --- a/chrome/browser/page_load_metrics/page_load_tracker.cc +++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -375,8 +375,9 @@ void PageLoadTracker::DidFinishSubFrameNavigation( content::NavigationHandle* navigation_handle) { + PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); for (const auto& observer : observers_) { - observer->OnDidFinishSubFrameNavigation(navigation_handle); + observer->OnDidFinishSubFrameNavigation(navigation_handle, extra_info); } }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index dbf20286..03f06bb 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/prerender/prerender_contents.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/site_isolation_policy.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/ui/browser_finder.h" @@ -82,7 +83,7 @@ #include "third_party/re2/src/re2/re2.h" #include "url/url_constants.h" -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h" #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #endif @@ -436,7 +437,7 @@ void ChromePasswordManagerClient::CheckSafeBrowsingReputation( const GURL& form_action, const GURL& frame_url) { -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) safe_browsing::PasswordProtectionService* pps = GetPasswordProtectionService(); if (pps) { @@ -451,7 +452,7 @@ popup_controller_->HideAndDestroy(); } -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) safe_browsing::PasswordProtectionService* ChromePasswordManagerClient::GetPasswordProtectionService() const { return safe_browsing::ChromePasswordProtectionService:: @@ -926,15 +927,24 @@ void ChromePasswordManagerClient::ShowManualFallbackForSaving( const autofill::PasswordForm& password_form) { + content::RenderFrameHost* frame = + password_manager_driver_bindings_.GetCurrentTargetFrame(); if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_driver_bindings_.GetCurrentTargetFrame(), - password_form, + frame, password_form, BadMessageReason::CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING)) return; password_manager::PasswordManagerDriver* driver = - driver_factory_->GetDriverForFrame( - password_manager_driver_bindings_.GetCurrentTargetFrame()); + driver_factory_->GetDriverForFrame(frame); GetPasswordManager()->ShowManualFallbackForSaving(driver, password_form); + + if (SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled()) { + // This function signals that the user is typing a password into + // |password_form|. Use this as a heuristic to start site-isolating the + // form's site. This is intended to be used primarily when full site + // isolation is not used, such as on Android. + content::SiteInstance::StartIsolatingSite( + frame->GetSiteInstance()->GetBrowserContext(), password_form.origin); + } } void ChromePasswordManagerClient::SameDocumentNavigation(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index ee5598a..1c806447 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -134,7 +134,7 @@ void HidePasswordGenerationPopup(); -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) safe_browsing::PasswordProtectionService* GetPasswordProtectionService() const override;
diff --git a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc index 945a22b..04d2782 100644 --- a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
@@ -626,7 +626,14 @@ DISALLOW_COPY_AND_ASSIGN(MachineLevelUserCloudPolicyPolicyFetchTest); }; -IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyPolicyFetchTest, Test) { +// Crashes on Win only. http://crbug.com/939261 +#if defined(OS_WIN) +#define MAYBE_Test DISABLED_Test +#else +#define MAYBE_Test Test +#endif + +IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyPolicyFetchTest, MAYBE_Test) { MachineLevelUserCloudPolicyManager* manager = g_browser_process->browser_policy_connector() ->machine_level_user_cloud_policy_manager();
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index b9276a7..e610f9ba 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -1009,25 +1009,44 @@ IN_PROC_BROWSER_TEST_P( PreviewsLitePageServerBrowserTest, DISABLE_ON_WIN_MAC_CHROMESOS(LitePagePreviewsReloadDisabled)) { - // Start with a non-preview load. - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_3G); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + {}, {previews::features::kPreviewsReloadsAreSoftOptOuts}); - ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); - VerifyPreviewNotLoaded(); + content::ReloadType tests[] = { + content::ReloadType::NORMAL, + content::ReloadType::BYPASSING_CACHE, + content::ReloadType::ORIGINAL_REQUEST_URL, + }; + for (content::ReloadType type : tests) { + // Start with a non-preview load. + g_browser_process->network_quality_tracker() + ->ReportEffectiveConnectionTypeForTesting( + net::EFFECTIVE_CONNECTION_TYPE_3G); - // Set the conditions so a Preview would trigger if not for the reload. - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_2G); - GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); - VerifyPreviewNotLoaded(); + ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); + VerifyPreviewNotLoaded(); + + // Set the conditions so a Preview would trigger if not for the reload. + g_browser_process->network_quality_tracker() + ->ReportEffectiveConnectionTypeForTesting( + net::EFFECTIVE_CONNECTION_TYPE_2G); + GetWebContents()->GetController().Reload(type, false); + VerifyPreviewNotLoaded(); + + // Verify that a reload on a preview page triggers a redirect back to the + // original page. + ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); + VerifyPreviewLoaded(); + + GetWebContents()->GetController().Reload(type, false); + VerifyPreviewNotLoaded(); + } } IN_PROC_BROWSER_TEST_P( PreviewsLitePageServerBrowserTest, - DISABLE_ON_WIN_MAC_CHROMESOS(ReloadingLitePagesDisablesLitePages)) { + DISABLE_ON_WIN_MAC_CHROMESOS(LitePagePreviewsReloadDisabled_SoftOptOut)) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitWithFeatures( {previews::features::kPreviewsReloadsAreSoftOptOuts}, {}); @@ -1037,10 +1056,6 @@ GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); VerifyPreviewNotLoaded(); - - // Check the the rule is still present. - ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); - VerifyPreviewNotLoaded(); } IN_PROC_BROWSER_TEST_P( @@ -1051,6 +1066,15 @@ VerifyPreviewLoaded(); VerifyInfoStatus(&histogram_tester, previews::ServerLitePageStatus::kSuccess); + PreviewsServiceFactory::GetForProfile( + Profile::FromBrowserContext(browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetBrowserContext())) + ->previews_ui_service() + ->previews_decider_impl() + ->SetIgnorePreviewsBlacklistDecision(false /* ignored */); + PreviewsUITabHelper::FromWebContents(GetWebContents()) ->ReloadWithoutPreviews(); VerifyPreviewNotLoaded(); @@ -1086,9 +1110,9 @@ VerifyInfoStatus(&histogram_tester, previews::ServerLitePageStatus::kRedirect); ClearDeciderState(); - histogram_tester.ExpectBucketCount( - "Previews.ServerLitePage.ServerResponse", - PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1); + histogram_tester.ExpectBucketCount( + "Previews.ServerLitePage.ServerResponse", + PreviewsLitePageNavigationThrottle::ServerResponse::kRedirect, 1); } {
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc index d7b2633..7bdacbf 100644 --- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc +++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -298,8 +298,6 @@ bool PreviewsLitePageNavigationThrottle::IsEligibleForPreview() const { DCHECK(navigation_handle()->IsInMainFrame()); - DCHECK_NE(navigation_handle()->GetReloadType(), - content::ReloadType::ORIGINAL_REQUEST_URL); if (data_reduction_proxy::HasURLRedirectCycle( navigation_handle()->GetRedirectChain()) || @@ -321,6 +319,8 @@ return false; } + DCHECK_EQ(navigation_handle()->GetReloadType(), content::ReloadType::NONE); + if (previews::IsLitePageRedirectPreviewDomain(navigation_handle()->GetURL())) return false;
diff --git a/chrome/browser/previews/previews_oneplatform_hints_browsertest.cc b/chrome/browser/previews/previews_oneplatform_hints_browsertest.cc new file mode 100644 index 0000000..000c27d --- /dev/null +++ b/chrome/browser/previews/previews_oneplatform_hints_browsertest.cc
@@ -0,0 +1,173 @@ +// Copyright 2019 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 <map> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/run_loop.h" +#include "base/task/post_task.h" +#include "base/task/task_scheduler/task_scheduler.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/metrics/subprocess_metrics_provider.h" +#include "chrome/browser/previews/previews_service.h" +#include "chrome/browser/previews/previews_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" +#include "components/optimization_guide/hints_component_info.h" +#include "components/optimization_guide/optimization_guide_service.h" +#include "components/optimization_guide/proto/hints.pb.h" +#include "components/optimization_guide/test_hints_component_creator.h" +#include "components/previews/content/previews_decider_impl.h" +#include "components/previews/content/previews_optimization_guide.h" +#include "components/previews/content/previews_ui_service.h" +#include "components/previews/core/previews_black_list.h" +#include "components/previews/core/previews_constants.h" +#include "components/previews/core/previews_features.h" +#include "components/previews/core/previews_switches.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/test/browser_test_utils.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "services/network/public/cpp/network_quality_tracker.h" + +namespace { + +// Fetch and calculate the total number of samples from all the bins for +// |histogram_name|. Note: from some browertests run (such as chromeos) there +// might be two profiles created, and this will return the total sample count +// across profiles. +int GetTotalHistogramSamples(const base::HistogramTester* histogram_tester, + const std::string& histogram_name) { + std::vector<base::Bucket> buckets = + histogram_tester->GetAllSamples(histogram_name); + int total = 0; + for (const auto& bucket : buckets) + total += bucket.count; + + return total; +} + +// Retries fetching |histogram_name| until it contains at least |count| samples. +int RetryForHistogramUntilCountReached( + const base::HistogramTester* histogram_tester, + const std::string& histogram_name, + int count) { + int total = 0; + while (true) { + base::TaskScheduler::GetInstance()->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + + total = GetTotalHistogramSamples(histogram_tester, histogram_name); + if (total >= count) + return total; + } +} + +} // namespace + +// This test class sets up everything but does not enable any features. +class PreviewsOnePlatformNoFeaturesBrowserTest : public InProcessBrowserTest { + public: + PreviewsOnePlatformNoFeaturesBrowserTest() = default; + ~PreviewsOnePlatformNoFeaturesBrowserTest() override = default; + + void SetUpOnMainThread() override { + https_server_.reset( + new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS)); + https_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews"); + ASSERT_TRUE(https_server_->Start()); + + InProcessBrowserTest::SetUpOnMainThread(); + } + + void SetUpCommandLine(base::CommandLine* cmd) override { + cmd->AppendSwitch("enable-spdy-proxy-auth"); + + // Due to race conditions, it's possible that blacklist data is not loaded + // at the time of first navigation. That may prevent Preview from + // triggering, and causing the test to flake. + cmd->AppendSwitch(previews::switches::kIgnorePreviewsBlacklist); + } + + const GURL& https_url() const { return https_url_; } + const base::HistogramTester* GetHistogramTester() { + return &histogram_tester_; + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + private: + void TearDownOnMainThread() override { + EXPECT_TRUE(https_server_->ShutdownAndWaitUntilComplete()); + + InProcessBrowserTest::TearDownOnMainThread(); + } + + std::unique_ptr<net::EmbeddedTestServer> https_server_; + GURL https_url_; + + base::HistogramTester histogram_tester_; + + DISALLOW_COPY_AND_ASSIGN(PreviewsOnePlatformNoFeaturesBrowserTest); +}; + +// This test class enables OnePlatform Hints. +class PreviewsOnePlatformHintsBrowserTest + : public PreviewsOnePlatformNoFeaturesBrowserTest { + public: + PreviewsOnePlatformHintsBrowserTest() = default; + + ~PreviewsOnePlatformHintsBrowserTest() override = default; + + void SetUp() override { + // Enabled OnePlatformHints with |kPreviewsOnePlatformHints|. + scoped_feature_list_.InitWithFeatures( + {previews::features::kPreviews, previews::features::kOptimizationHints, + previews::features::kPreviewsOnePlatformHints}, + {}); + // Call to inherited class to match same set up with feature flags added. + PreviewsOnePlatformNoFeaturesBrowserTest::SetUp(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(PreviewsOnePlatformHintsBrowserTest); +}; + +// This test creates new browser with no profile and loads a random page with +// the feature flags enables the PreviewsOnePlatformHints. We confirm that the +// top_host_provider_impl executes and does not crash by checking UMA +// histograms for the total number of TopEngagementSites and +// the total number of sites returned controlled by the experiments flag +// |max_oneplatform_update_hosts|. +IN_PROC_BROWSER_TEST_F(PreviewsOnePlatformHintsBrowserTest, + OnePlatformHintsEnabled) { + const base::HistogramTester* histogram_tester = GetHistogramTester(); + + // Expect that the browser initialization will record at least one sample + // in each of the follow histograms as One Platform Hints are enabled. + EXPECT_GE(RetryForHistogramUntilCountReached( + histogram_tester, + "Previews.HintsFetcher.GetHintsRequest.HostCount", 1), + 1); +} + +IN_PROC_BROWSER_TEST_F(PreviewsOnePlatformNoFeaturesBrowserTest, + OnePlatformNoFeatures) { + const base::HistogramTester* histogram_tester = GetHistogramTester(); + + // Expect that the histogram for HintsFetcher to be 0 because the OnePlatform + // is not enabled. + histogram_tester->ExpectTotalCount( + "Previews.HintsFetcher.GetHintsRequest.HostCount", 0); +}
diff --git a/chrome/browser/previews/previews_service.cc b/chrome/browser/previews/previews_service.cc index c9c03b60..d917986 100644 --- a/chrome/browser/previews/previews_service.cc +++ b/chrome/browser/previews/previews_service.cc
@@ -102,7 +102,10 @@ } PreviewsService::PreviewsService(content::BrowserContext* browser_context) - : previews_lite_page_decider_( + : previews_top_host_provider_( + std::make_unique<previews::PreviewsTopHostProviderImpl>( + browser_context)), + previews_lite_page_decider_( std::make_unique<PreviewsLitePageDecider>(browser_context)) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } @@ -133,7 +136,8 @@ profile_path.Append(chrome::kPreviewsOptOutDBFilename)), optimization_guide_service ? std::make_unique<previews::PreviewsOptimizationGuide>( - optimization_guide_service, ui_task_runner, profile_path) + optimization_guide_service, ui_task_runner, profile_path, + previews_top_host_provider_.get()) : nullptr, base::Bind(&IsPreviewsTypeEnabled), std::make_unique<previews::PreviewsLogger>(), GetAllowedPreviews(),
diff --git a/chrome/browser/previews/previews_service.h b/chrome/browser/previews/previews_service.h index 840eee7..d12077b 100644 --- a/chrome/browser/previews/previews_service.h +++ b/chrome/browser/previews/previews_service.h
@@ -6,10 +6,13 @@ #define CHROME_BROWSER_PREVIEWS_PREVIEWS_SERVICE_H_ #include <memory> +#include <string> +#include <vector> #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" +#include "chrome/browser/previews/previews_top_host_provider_impl.h" #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_data.h" #include "components/keyed_service/core/keyed_service.h" @@ -26,6 +29,7 @@ } namespace previews { +class PreviewsTopHostProviderImpl; class PreviewsUIService; } @@ -69,6 +73,10 @@ static blacklist::BlacklistData::AllowedTypesAndVersions GetAllowedPreviews(); private: + // The top site provider for use with previews. + std::unique_ptr<previews::PreviewsTopHostProviderImpl> + previews_top_host_provider_; + // The previews UI thread service. std::unique_ptr<previews::PreviewsUIService> previews_ui_service_;
diff --git a/chrome/browser/previews/previews_top_host_provider_impl.cc b/chrome/browser/previews/previews_top_host_provider_impl.cc new file mode 100644 index 0000000..673e7dd7 --- /dev/null +++ b/chrome/browser/previews/previews_top_host_provider_impl.cc
@@ -0,0 +1,50 @@ +// Copyright 2019 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/previews/previews_top_host_provider_impl.h" + +#include "base/metrics/histogram_macros.h" +#include "chrome/browser/engagement/site_engagement_details.mojom.h" +#include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_thread.h" + +namespace previews { + +PreviewsTopHostProviderImpl::PreviewsTopHostProviderImpl( + content::BrowserContext* browser_context) + : browser_context_(browser_context) {} + +PreviewsTopHostProviderImpl::~PreviewsTopHostProviderImpl() {} + +std::vector<std::string> PreviewsTopHostProviderImpl::GetTopHosts( + size_t max_sites) const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(browser_context_); + + std::vector<std::string> top_hosts; + top_hosts.reserve(max_sites); + + // Create SiteEngagementService to request site engagement scores. + Profile* profile = Profile::FromBrowserContext(browser_context_); + SiteEngagementService* engagement_service = + SiteEngagementService::Get(profile); + + // Create a vector of the top hosts by engagement score up to |max_sites| + // size. Currently utilizes just the first |max_sites| entries. + // TODO(crbug.com/932707): Select TOP HTTPS hosts from site engagement. + std::vector<mojom::SiteEngagementDetails> engagement_details = + engagement_service->GetAllDetails(); + for (const auto& detail : engagement_details) { + if (top_hosts.size() <= max_sites) + top_hosts.push_back(detail.origin.host()); + else + break; + } + + return top_hosts; +} + +} // namespace previews
diff --git a/chrome/browser/previews/previews_top_host_provider_impl.h b/chrome/browser/previews/previews_top_host_provider_impl.h new file mode 100644 index 0000000..c279f5f6 --- /dev/null +++ b/chrome/browser/previews/previews_top_host_provider_impl.h
@@ -0,0 +1,43 @@ +// Copyright 2019 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_PREVIEWS_PREVIEWS_TOP_HOST_PROVIDER_IMPL_H_ +#define CHROME_BROWSER_PREVIEWS_PREVIEWS_TOP_HOST_PROVIDER_IMPL_H_ + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/sequence_checker.h" +#include "components/previews/content/previews_top_host_provider.h" + +namespace content { +class BrowserContext; +} + +namespace previews { + +// An implementation of the PreviewTopHostProvider for getting the top sites +// based on site engagement scores. +class PreviewsTopHostProviderImpl : public PreviewsTopHostProvider { + public: + explicit PreviewsTopHostProviderImpl(content::BrowserContext* BrowserContext); + ~PreviewsTopHostProviderImpl() override; + + std::vector<std::string> GetTopHosts(size_t max_sites) const override; + + private: + // |browser_context_| is used for interaction with the SiteEngagementService + // and the embedder should guarantee that it is non-null during the lifetime + // of |this|. + content::BrowserContext* browser_context_; + + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(PreviewsTopHostProviderImpl); +}; + +} // namespace previews + +#endif // CHROME_BROWSER_PREVIEWS_PREVIEWS_TOP_HOST_PROVIDER_IMPL_H_
diff --git a/chrome/browser/profiles/profile_attributes_storage.cc b/chrome/browser/profiles/profile_attributes_storage.cc index 615be3a..e4373d7 100644 --- a/chrome/browser/profiles/profile_attributes_storage.cc +++ b/chrome/browser/profiles/profile_attributes_storage.cc
@@ -195,7 +195,9 @@ name = l10n_util::GetStringFUTF16(IDS_NEW_NUMBERED_PROFILE_NAME, base::NumberToString16(name_index)); #else - if (icon_index < profiles::GetGenericAvatarIconCount()) { + // TODO(crbug.com/937834): Clean up this code. + if (icon_index < profiles::GetGenericAvatarIconCount() || + profiles::IsModernAvatarIconIndex(icon_index)) { name = l10n_util::GetStringFUTF16Int(IDS_NUMBERED_PROFILE_NAME, name_index); } else {
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc index ace1174..8774926 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util.cc +++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/profiles/profile_avatar_icon_util.h" +#include <algorithm> #include <memory> #include <utility> #include <vector> @@ -16,6 +17,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/values.h" +#include "build/build_config.h" #include "cc/paint/paint_flags.h" #include "chrome/browser/browser_process.h" #include "chrome/common/chrome_paths.h" @@ -38,6 +40,9 @@ // Helper methods for transforming and drawing avatar icons. namespace { +const int kOldAvatarIconWidth = 38; +const int kOldAvatarIconHeight = 31; + // Determine what the scaled height of the avatar icon should be for a // specified width, to preserve the aspect ratio. int GetScaledAvatarHeightForWidth(int width, const gfx::ImageSkia& avatar) { @@ -239,28 +244,33 @@ int label_id; }; -const int kAvatarIconWidth = 38; -const int kAvatarIconHeight = 31; -const SkColor kAvatarTutorialBackgroundColor = SkColorSetRGB(0x42, 0x85, 0xf4); -const SkColor kAvatarTutorialContentTextColor = SkColorSetRGB(0xc6, 0xda, 0xfc); -const SkColor kAvatarBubbleAccountsBackgroundColor = +constexpr int kAvatarIconSize = 96; +constexpr SkColor kAvatarTutorialBackgroundColor = + SkColorSetRGB(0x42, 0x85, 0xf4); +constexpr SkColor kAvatarTutorialContentTextColor = + SkColorSetRGB(0xc6, 0xda, 0xfc); +constexpr SkColor kAvatarBubbleAccountsBackgroundColor = SkColorSetRGB(0xf3, 0xf3, 0xf3); -const SkColor kAvatarBubbleGaiaBackgroundColor = +constexpr SkColor kAvatarBubbleGaiaBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); -const SkColor kUserManagerBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); +constexpr SkColor kUserManagerBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); -const char kDefaultUrlPrefix[] = "chrome://theme/IDR_PROFILE_AVATAR_"; -const char kGAIAPictureFileName[] = "Google Profile Picture.png"; -const char kHighResAvatarFolderName[] = "Avatars"; +constexpr char kDefaultUrlPrefix[] = "chrome://theme/IDR_PROFILE_AVATAR_"; +constexpr char kGAIAPictureFileName[] = "Google Profile Picture.png"; +constexpr char kHighResAvatarFolderName[] = "Avatars"; // The size of the function-static kDefaultAvatarIconResources array below. -const size_t kDefaultAvatarIconsCount = 27; +#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +constexpr size_t kDefaultAvatarIconsCount = 38; +#else +constexpr size_t kDefaultAvatarIconsCount = 27; +#endif // The first 8 icons are generic. -const size_t kGenericAvatarIconsCount = 8; +constexpr size_t kGenericAvatarIconsCount = 8; // The avatar used as a placeholder (grey silhouette). -const size_t kPlaceholderAvatarIndex = 26; +constexpr size_t kPlaceholderAvatarIndex = 26; gfx::Image GetSizedAvatarIcon(const gfx::Image& image, bool is_rectangle, @@ -291,8 +301,8 @@ gfx::Image GetAvatarIconForWebUI(const gfx::Image& image, bool is_rectangle) { - return GetSizedAvatarIcon(image, is_rectangle, - kAvatarIconWidth, kAvatarIconHeight); + return GetSizedAvatarIcon(image, is_rectangle, kAvatarIconSize, + kAvatarIconSize); } gfx::Image GetAvatarIconForTitleBar(const gfx::Image& image, @@ -300,11 +310,10 @@ int dst_width, int dst_height) { // The image requires no border or resizing. - if (!is_gaia_image && image.Height() <= kAvatarIconHeight) + if (!is_gaia_image && image.Height() <= kAvatarIconSize) return image; - int size = std::min(std::min(kAvatarIconWidth, kAvatarIconHeight), - std::min(dst_width, dst_height)); + int size = std::min(kAvatarIconSize, std::min(dst_width, dst_height)); gfx::Size dst_size(dst_width, dst_height); // Source for a sized icon drawn at the bottom center of the canvas, @@ -321,16 +330,17 @@ SkBitmap GetAvatarIconAsSquare(const SkBitmap& source_bitmap, int scale_factor) { SkBitmap square_bitmap; - if ((source_bitmap.width() == scale_factor * profiles::kAvatarIconWidth) && - (source_bitmap.height() == scale_factor * profiles::kAvatarIconHeight)) { - // Shave a couple of columns so the |source_bitmap| is more square. So when - // resized to a square aspect ratio it looks pretty. - gfx::Rect frame(scale_factor * profiles::kAvatarIconWidth, - scale_factor * profiles::kAvatarIconHeight); + if ((source_bitmap.width() == scale_factor * kOldAvatarIconWidth) && + (source_bitmap.height() == scale_factor * kOldAvatarIconHeight)) { + // If |source_bitmap| matches the old avatar icon dimensions, i.e. it's an + // old avatar icon, shave a couple of columns so the |source_bitmap| is more + // square. So when resized to a square aspect ratio it looks pretty. + gfx::Rect frame(scale_factor * profiles::kAvatarIconSize, + scale_factor * profiles::kAvatarIconSize); frame.Inset(scale_factor * 2, 0, scale_factor * 2, 0); source_bitmap.extractSubset(&square_bitmap, gfx::RectToSkIRect(frame)); } else { - // If not the avatar icon's aspect ratio, the image should be square. + // If it's not an old avatar icon, the image should be square. DCHECK(source_bitmap.width() == source_bitmap.height()); square_bitmap = source_bitmap; } @@ -350,6 +360,23 @@ return kPlaceholderAvatarIndex; } +size_t GetModernAvatarIconStartIndex() { +#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) + return GetPlaceholderAvatarIndex() + 1; +#else + // Only use the placeholder avatar on ChromeOS and Android. + // TODO(crbug.com/937834): Clean up code and remove code dependencies from + // Android and ChromeOS. Avatar icons from this file are not used on these + // platforms. + return GetPlaceholderAvatarIndex(); +#endif +} + +bool IsModernAvatarIconIndex(size_t icon_index) { + return icon_index >= GetModernAvatarIconStartIndex() && + icon_index < GetDefaultAvatarIconCount(); +} + int GetPlaceholderAvatarIconResourceID() { return IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE; } @@ -361,85 +388,74 @@ const IconResourceInfo* GetDefaultAvatarIconResourceInfo(size_t index) { CHECK_LT(index, kDefaultAvatarIconsCount); static const IconResourceInfo resource_info[kDefaultAvatarIconsCount] = { - {IDR_PROFILE_AVATAR_0, - "avatar_generic.png", - IDS_DEFAULT_AVATAR_LABEL_0}, - {IDR_PROFILE_AVATAR_1, - "avatar_generic_aqua.png", - IDS_DEFAULT_AVATAR_LABEL_1}, - {IDR_PROFILE_AVATAR_2, - "avatar_generic_blue.png", - IDS_DEFAULT_AVATAR_LABEL_2}, - {IDR_PROFILE_AVATAR_3, - "avatar_generic_green.png", - IDS_DEFAULT_AVATAR_LABEL_3}, - {IDR_PROFILE_AVATAR_4, - "avatar_generic_orange.png", - IDS_DEFAULT_AVATAR_LABEL_4}, - {IDR_PROFILE_AVATAR_5, - "avatar_generic_purple.png", - IDS_DEFAULT_AVATAR_LABEL_5}, - {IDR_PROFILE_AVATAR_6, - "avatar_generic_red.png", - IDS_DEFAULT_AVATAR_LABEL_6}, - {IDR_PROFILE_AVATAR_7, - "avatar_generic_yellow.png", - IDS_DEFAULT_AVATAR_LABEL_7}, - {IDR_PROFILE_AVATAR_8, - "avatar_secret_agent.png", - IDS_DEFAULT_AVATAR_LABEL_8}, - {IDR_PROFILE_AVATAR_9, - "avatar_superhero.png", - IDS_DEFAULT_AVATAR_LABEL_9}, - {IDR_PROFILE_AVATAR_10, - "avatar_volley_ball.png", - IDS_DEFAULT_AVATAR_LABEL_10}, - {IDR_PROFILE_AVATAR_11, - "avatar_businessman.png", - IDS_DEFAULT_AVATAR_LABEL_11}, - {IDR_PROFILE_AVATAR_12, - "avatar_ninja.png", - IDS_DEFAULT_AVATAR_LABEL_12}, - {IDR_PROFILE_AVATAR_13, - "avatar_alien.png", - IDS_DEFAULT_AVATAR_LABEL_13}, - {IDR_PROFILE_AVATAR_14, - "avatar_awesome.png", - IDS_DEFAULT_AVATAR_LABEL_14}, - {IDR_PROFILE_AVATAR_15, - "avatar_flower.png", - IDS_DEFAULT_AVATAR_LABEL_15}, - {IDR_PROFILE_AVATAR_16, - "avatar_pizza.png", - IDS_DEFAULT_AVATAR_LABEL_16}, - {IDR_PROFILE_AVATAR_17, - "avatar_soccer.png", - IDS_DEFAULT_AVATAR_LABEL_17}, - {IDR_PROFILE_AVATAR_18, - "avatar_burger.png", - IDS_DEFAULT_AVATAR_LABEL_18}, - {IDR_PROFILE_AVATAR_19, - "avatar_cat.png", - IDS_DEFAULT_AVATAR_LABEL_19}, - {IDR_PROFILE_AVATAR_20, - "avatar_cupcake.png", - IDS_DEFAULT_AVATAR_LABEL_20}, - {IDR_PROFILE_AVATAR_21, - "avatar_dog.png", - IDS_DEFAULT_AVATAR_LABEL_21}, - {IDR_PROFILE_AVATAR_22, - "avatar_horse.png", - IDS_DEFAULT_AVATAR_LABEL_22}, - {IDR_PROFILE_AVATAR_23, - "avatar_margarita.png", - IDS_DEFAULT_AVATAR_LABEL_23}, - {IDR_PROFILE_AVATAR_24, - "avatar_note.png", - IDS_DEFAULT_AVATAR_LABEL_24}, - {IDR_PROFILE_AVATAR_25, - "avatar_sun_cloud.png", - IDS_DEFAULT_AVATAR_LABEL_25}, - {IDR_PROFILE_AVATAR_26, NULL, -1}, + // Old avatar icons: + {IDR_PROFILE_AVATAR_0, "avatar_generic.png", IDS_DEFAULT_AVATAR_LABEL_0}, + {IDR_PROFILE_AVATAR_1, "avatar_generic_aqua.png", + IDS_DEFAULT_AVATAR_LABEL_1}, + {IDR_PROFILE_AVATAR_2, "avatar_generic_blue.png", + IDS_DEFAULT_AVATAR_LABEL_2}, + {IDR_PROFILE_AVATAR_3, "avatar_generic_green.png", + IDS_DEFAULT_AVATAR_LABEL_3}, + {IDR_PROFILE_AVATAR_4, "avatar_generic_orange.png", + IDS_DEFAULT_AVATAR_LABEL_4}, + {IDR_PROFILE_AVATAR_5, "avatar_generic_purple.png", + IDS_DEFAULT_AVATAR_LABEL_5}, + {IDR_PROFILE_AVATAR_6, "avatar_generic_red.png", + IDS_DEFAULT_AVATAR_LABEL_6}, + {IDR_PROFILE_AVATAR_7, "avatar_generic_yellow.png", + IDS_DEFAULT_AVATAR_LABEL_7}, + {IDR_PROFILE_AVATAR_8, "avatar_secret_agent.png", + IDS_DEFAULT_AVATAR_LABEL_8}, + {IDR_PROFILE_AVATAR_9, "avatar_superhero.png", IDS_DEFAULT_AVATAR_LABEL_9}, + {IDR_PROFILE_AVATAR_10, "avatar_volley_ball.png", + IDS_DEFAULT_AVATAR_LABEL_10}, + {IDR_PROFILE_AVATAR_11, "avatar_businessman.png", + IDS_DEFAULT_AVATAR_LABEL_11}, + {IDR_PROFILE_AVATAR_12, "avatar_ninja.png", IDS_DEFAULT_AVATAR_LABEL_12}, + {IDR_PROFILE_AVATAR_13, "avatar_alien.png", IDS_DEFAULT_AVATAR_LABEL_13}, + {IDR_PROFILE_AVATAR_14, "avatar_awesome.png", IDS_DEFAULT_AVATAR_LABEL_14}, + {IDR_PROFILE_AVATAR_15, "avatar_flower.png", IDS_DEFAULT_AVATAR_LABEL_15}, + {IDR_PROFILE_AVATAR_16, "avatar_pizza.png", IDS_DEFAULT_AVATAR_LABEL_16}, + {IDR_PROFILE_AVATAR_17, "avatar_soccer.png", IDS_DEFAULT_AVATAR_LABEL_17}, + {IDR_PROFILE_AVATAR_18, "avatar_burger.png", IDS_DEFAULT_AVATAR_LABEL_18}, + {IDR_PROFILE_AVATAR_19, "avatar_cat.png", IDS_DEFAULT_AVATAR_LABEL_19}, + {IDR_PROFILE_AVATAR_20, "avatar_cupcake.png", IDS_DEFAULT_AVATAR_LABEL_20}, + {IDR_PROFILE_AVATAR_21, "avatar_dog.png", IDS_DEFAULT_AVATAR_LABEL_21}, + {IDR_PROFILE_AVATAR_22, "avatar_horse.png", IDS_DEFAULT_AVATAR_LABEL_22}, + {IDR_PROFILE_AVATAR_23, "avatar_margarita.png", + IDS_DEFAULT_AVATAR_LABEL_23}, + {IDR_PROFILE_AVATAR_24, "avatar_note.png", IDS_DEFAULT_AVATAR_LABEL_24}, + {IDR_PROFILE_AVATAR_25, "avatar_sun_cloud.png", + IDS_DEFAULT_AVATAR_LABEL_25}, + + // Placeholder avatar icon: + {IDR_PROFILE_AVATAR_26, NULL, -1}, + +#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) + // Modern avatar icons: + {IDR_PROFILE_AVATAR_27, "avatar_origami_cat.png", + IDS_DEFAULT_AVATAR_LABEL_27}, + {IDR_PROFILE_AVATAR_28, "avatar_origami_corgi.png", + IDS_DEFAULT_AVATAR_LABEL_28}, + {IDR_PROFILE_AVATAR_29, "avatar_origami_dragon.png", + IDS_DEFAULT_AVATAR_LABEL_29}, + {IDR_PROFILE_AVATAR_30, "avatar_origami_elephant.png", + IDS_DEFAULT_AVATAR_LABEL_30}, + {IDR_PROFILE_AVATAR_31, "avatar_origami_fox.png", + IDS_DEFAULT_AVATAR_LABEL_31}, + {IDR_PROFILE_AVATAR_32, "avatar_origami_monkey.png", + IDS_DEFAULT_AVATAR_LABEL_32}, + {IDR_PROFILE_AVATAR_33, "avatar_origami_panda.png", + IDS_DEFAULT_AVATAR_LABEL_33}, + {IDR_PROFILE_AVATAR_34, "avatar_origami_penguin.png", + IDS_DEFAULT_AVATAR_LABEL_34}, + {IDR_PROFILE_AVATAR_35, "avatar_origami_pinkbutterfly.png", + IDS_DEFAULT_AVATAR_LABEL_35}, + {IDR_PROFILE_AVATAR_36, "avatar_origami_rabbit.png", + IDS_DEFAULT_AVATAR_LABEL_36}, + {IDR_PROFILE_AVATAR_37, "avatar_origami_unicorn.png", + IDS_DEFAULT_AVATAR_LABEL_37}, +#endif }; return &resource_info[index]; } @@ -495,19 +511,20 @@ return false; } -std::unique_ptr<base::ListValue> GetDefaultProfileAvatarIconsAndLabels() { +std::unique_ptr<base::ListValue> GetDefaultProfileAvatarIconsAndLabels( + size_t selected_avatar_idx) { std::unique_ptr<base::ListValue> avatars(new base::ListValue()); - const size_t placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex(); - for (size_t i = 0; i < profiles::GetDefaultAvatarIconCount() && - i != placeholder_avatar_index; - ++i) { + for (size_t i = GetModernAvatarIconStartIndex(); + i < GetDefaultAvatarIconCount(); ++i) { std::unique_ptr<base::DictionaryValue> avatar_info( new base::DictionaryValue()); avatar_info->SetString("url", profiles::GetDefaultAvatarIconUrl(i)); avatar_info->SetString( "label", l10n_util::GetStringUTF16( profiles::GetDefaultAvatarLabelResourceIDAtIndex(i))); + if (i == selected_avatar_idx) + avatar_info->SetBoolean("selected", true); avatars->Append(std::move(avatar_info)); }
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.h b/chrome/browser/profiles/profile_avatar_icon_util.h index dec4541..c2784892 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util.h +++ b/chrome/browser/profiles/profile_avatar_icon_util.h
@@ -31,8 +31,7 @@ extern const char kHighResAvatarFolderName[]; // Avatar formatting. -extern const int kAvatarIconWidth; -extern const int kAvatarIconHeight; +extern const int kAvatarIconSize; extern const SkColor kAvatarTutorialBackgroundColor; extern const SkColor kAvatarTutorialContentTextColor; extern const SkColor kAvatarBubbleAccountsBackgroundColor; @@ -83,6 +82,13 @@ // Gets the index for the (grey silhouette) avatar used as a placeholder. size_t GetPlaceholderAvatarIndex(); +// Gets the start index of the modern profile avatar icons. +size_t GetModernAvatarIconStartIndex(); + +// Returns whether |icon_index| corresponds to one of the modern profile avatar +// icons. +bool IsModernAvatarIconIndex(size_t icon_index); + // Gets the resource ID of the placeholder avatar icon. int GetPlaceholderAvatarIconResourceID(); @@ -113,8 +119,10 @@ // Returns a list of dictionaries containing the default profile avatar icons as // well as avatar labels used for accessibility purposes. The list is ordered -// according to the avatars' default order. -std::unique_ptr<base::ListValue> GetDefaultProfileAvatarIconsAndLabels(); +// according to the avatars' default order. If |selected_avatar_idx| is one of +// the available indices, the corresponding avatar is marked as selected. +std::unique_ptr<base::ListValue> GetDefaultProfileAvatarIconsAndLabels( + size_t selected_avatar_idx = SIZE_MAX); // This method tries to find a random avatar index that is not in // |used_icon_indices|. If there is no such index, a random index is returned.
diff --git a/chrome/browser/profiles/profile_avatar_icon_util_unittest.cc b/chrome/browser/profiles/profile_avatar_icon_util_unittest.cc index 02655cfa4..1eff1ea 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util_unittest.cc +++ b/chrome/browser/profiles/profile_avatar_icon_util_unittest.cc
@@ -64,7 +64,7 @@ // Test that a rectangular picture is changed. gfx::Image rect_picture(gfx::test::CreateImage()); - gfx::Size size(profiles::kAvatarIconWidth, profiles::kAvatarIconHeight); + gfx::Size size(profiles::kAvatarIconSize, profiles::kAvatarIconSize); gfx::Image result2 = profiles::GetAvatarIconForWebUI(rect_picture, true); VerifyScaling(result2, size);
diff --git a/chrome/browser/profiles/profile_metrics.cc b/chrome/browser/profiles/profile_metrics.cc index 91b9c758..6b771c5 100644 --- a/chrome/browser/profiles/profile_metrics.cc +++ b/chrome/browser/profiles/profile_metrics.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/chrome_signin_helper.h" #include "chrome/browser/ui/browser_finder.h" @@ -236,7 +237,6 @@ } void ProfileMetrics::LogProfileAvatarSelection(size_t icon_index) { - DCHECK(icon_index < NUM_PROFILE_AVATAR_METRICS); ProfileAvatar icon_name = AVATAR_UNKNOWN; switch (icon_index) { case 0: @@ -320,11 +320,12 @@ case 26: icon_name = AVATAR_PLACEHOLDER; break; - case 28: + case SIZE_MAX: icon_name = AVATAR_GAIA; break; - default: // We should never actually get here. - NOTREACHED(); + default: + DCHECK(profiles::IsModernAvatarIconIndex(icon_index)); + // TODO(crbug.com/937834): Log modern avatar selection. break; } UMA_HISTOGRAM_ENUMERATION("Profile.Avatar", icon_name, @@ -391,7 +392,7 @@ void ProfileMetrics::LogProfileSwitchGaia(ProfileGaia metric) { if (metric == GAIA_OPT_IN) - LogProfileAvatarSelection(AVATAR_GAIA); + LogProfileAvatarSelection(SIZE_MAX); UMA_HISTOGRAM_ENUMERATION("Profile.SwitchGaiaPhotoSettings", metric, NUM_PROFILE_GAIA_METRICS);
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc index 6466c068..e1fd9ec 100644 --- a/chrome/browser/profiles/profile_shortcut_manager_win.cc +++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -86,10 +86,10 @@ // Incrementing this number will cause profile icons to be regenerated on // profile startup (it should be incremented whenever the product/avatar icons // change, etc). -const int kCurrentProfileIconVersion = 5; +const int kCurrentProfileIconVersion = 6; -// 2x sized profile avatar icons. Mirrors |kDefaultAvatarIconResources| in -// profile_info_cache.cc. +// 2x sized versions of the old profile avatar icons. +// TODO(crbug.com/937834): Clean this up. const int kProfileAvatarIconResources2x[] = { IDR_PROFILE_AVATAR_2X_0, IDR_PROFILE_AVATAR_2X_1, IDR_PROFILE_AVATAR_2X_2, IDR_PROFILE_AVATAR_2X_3, @@ -807,9 +807,6 @@ ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) : profile_manager_(manager) { - DCHECK_EQ(base::size(kProfileAvatarIconResources2x), - profiles::GetDefaultAvatarIconCount()); - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); @@ -999,11 +996,18 @@ const size_t icon_index = entry->GetAvatarIconIndex(); const int resource_id_1x = profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index); - const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; - // Make a copy of the SkBitmaps to ensure that we can safely use the image - // data on the thread we post to. + // Make a copy of the SkBitmap to ensure that we can safely use the + // image data on the thread we post to. params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x); - params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x); + + if (profiles::IsModernAvatarIconIndex(icon_index)) { + // Modern avatars are large(192px) by default, which makes them big + // enough for 2x. + params.avatar_image_2x = params.avatar_image_1x; + } else { + const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; + params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x); + } } } base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()})
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/layout.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/layout.js index 760c787..d58a115 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/layout.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/layout.js
@@ -115,11 +115,6 @@ cca.state.set('max-wnd', fullWindow); cca.state.set('tall', tall); - var [letterboxW, letterboxH] = this.updatePreviewSize_(fullWindow); - var [halfW, halfH] = [letterboxW / 2, letterboxH / 2]; - var [rightBox, bottomBox, leftBox, topBox] = [halfW, halfH, halfW, halfH]; - - // Shift preview to accommodate the shutter in letterbox if applicable. var dimens = (shutter) => { // These following constants need kept in sync with relevant values in css. // preset: button-size + preset-margin + min-margin @@ -128,18 +123,22 @@ // baseline: preset-baseline return shutter ? [100, 88, 12, 56] : [76, 56, 20, 48]; }; + + var [letterboxW, letterboxH] = this.updatePreviewSize_(fullWindow); + var [halfW, halfH] = [letterboxW / 2, letterboxH / 2]; + + // Shift preview to accommodate the shutter in letterbox if applicable. var accommodate = (measure) => { var [, leastShutter] = dimens(true); return (measure > leastShutter) && (measure < leastShutter * 2); }; - if (cca.state.set('shift-preview-left', - fullWindow && tabletLandscape && accommodate(letterboxW))) { - [rightBox, leftBox] = [letterboxW, 0]; - } - if (cca.state.set('shift-preview-top', - fullWindow && !tabletLandscape && accommodate(letterboxH))) { - [bottomBox, topBox] = [letterboxH, 0]; - } + var cond = fullWindow && tabletLandscape && accommodate(letterboxW); + var [rightBox, leftBox] = cond ? [letterboxW, 0] : [halfW, halfW]; + cca.state.set('shift-preview-left', cond); + + cond = fullWindow && !tabletLandscape && accommodate(letterboxH); + var [bottomBox, topBox] = cond ? [letterboxH, 0] : [halfH, halfH]; + cca.state.set('shift-preview-top', cond); // Shift buttons' stripes if necessary. Buttons are either fully on letterbox // or preview while the shutter/options keep minimum margin to either edges. @@ -150,11 +149,12 @@ }; var shift = (stripe, name, measure, shutter) => { var [preset, least, gap, baseline] = dimens(shutter); - if (cca.state.set('shift-' + name + '-stripe', - measure > gap && measure < preset)) { + cond = measure > gap && measure < preset; + if (cond) { baseline = calc(measure, least); stripe.setProperty(name, baseline + 'px'); } + cca.state.set('shift-' + name + '-stripe', cond); // Return shutter's baseline in letterbox if applicable. return (shutter && baseline < measure) ? baseline : 0; };
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 35857cd..5cb13f8 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -228,9 +228,11 @@ /** * @override */ - navigateToRange: function(range, opt_focus, opt_speechProps) { + navigateToRange: function( + range, opt_focus, opt_speechProps, opt_skipSettingSelection) { opt_focus = opt_focus === undefined ? true : opt_focus; opt_speechProps = opt_speechProps || {}; + opt_skipSettingSelection = opt_skipSettingSelection || false; var prevRange = this.currentRange_; // Specialization for math output. @@ -249,7 +251,8 @@ var selectedRange; var msg; - if (this.pageSel_ && this.pageSel_.isValid() && range.isValid()) { + if (this.pageSel_ && this.pageSel_.isValid() && range.isValid() && + !opt_skipSettingSelection) { // Suppress hints. o.withoutHints(); @@ -291,7 +294,7 @@ if (this.pageSel_) this.pageSel_.select(); } - } else { + } else if (!opt_skipSettingSelection) { // Ensure we don't select the editable when we first encounter it. var lca = null; if (range.start.node && prevRange.start.node) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs index f711c2a..20df0b4 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1922,33 +1922,3 @@ .replay(); }); }); - -TEST_F('ChromeVoxBackgroundTest', 'AutoCompleteChanged', function() { - var mockFeedback = this.createMockFeedback(); - this.runWithLoadedTree(function() {/* - <div><input type="text" aria-autocomplete="off"></input></div> - <script> - var div = document.querySelector('div'); - var input = div.firstElementChild; - var completion = input.getAttribute('aria-autocomplete'); - div.addEventListener('click', () => { - completion = completion == 'off' ? 'both' : 'off'; - input.setAttribute('aria-autocomplete', completion); - }); - </script> - */}, function(root) { - var change = root.firstChild.doDefault.bind(root.firstChild); - mockFeedback.expectSpeech('Edit text') - .clearPendingOutput() - .call(change) - .expectSpeech('Edit text') - .call(change) - .expectSpeech('Edit text') - .call(change) - .expectNextSpeechUtteranceIsNot( - 'Press up or down arrow for auto completions.') - .expectSpeech('Edit text') - .expectSpeech('Press up or down arrow for auto completions.') - .replay(); - }); -});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/chromevox_state.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/chromevox_state.js index e635d8b..576336e 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/chromevox_state.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/chromevox_state.js
@@ -78,6 +78,8 @@ * @param {!cursors.Range} range The new range. * @param {boolean=} opt_focus Focus the range; defaults to true. * @param {Object=} opt_speechProps Speech properties. + * @param {boolean=} opt_skipSettingSelection If true, does not set + * the selection, otherwise it does by default. */ navigateToRange: goog.abstractMethod,
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js index 09b80f93..54527b7e 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -297,6 +297,7 @@ var skipSync = false; var didNavigate = false; var tryScrolling = true; + var skipSettingSelection = false; switch (command) { case 'nextCharacter': didNavigate = true; @@ -379,10 +380,12 @@ dir = Dir.BACKWARD; pred = AutomationPredicate.image; predErrorMsg = 'no_previous_graphic'; + skipSettingSelection = true; break; case 'nextGraphic': pred = AutomationPredicate.image; predErrorMsg = 'no_next_graphic'; + skipSettingSelection = true; break; case 'nextHeading': pred = AutomationPredicate.heading; @@ -1024,8 +1027,10 @@ } } - if (current) - ChromeVoxState.instance.navigateToRange(current, undefined, speechProps); + if (current) { + ChromeVoxState.instance.navigateToRange( + current, undefined, speechProps, skipSettingSelection); + } return false; };
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js index 641a4bf2..cd92f93 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
@@ -230,9 +230,10 @@ * @param {!AutomationEvent} evt */ onAriaAttributeChanged: function(evt) { - // Don't report changes on non-focused, richly editables. - if (evt.target.state[StateType.RICHLY_EDITABLE] && - !evt.target.state[StateType.FOCUSED]) + // Don't report changes on editable nodes since they interfere with text + // selection changes. Users can query via Search+k for the current state of + // the text field (which would also report the entire value). + if (evt.target.state[StateType.EDITABLE]) return; // Only report attribute changes on some *Option roles if it is selected.
diff --git a/chrome/browser/resources/chromeos/login/apps_menu.js b/chrome/browser/resources/chromeos/login/apps_menu.js deleted file mode 100644 index cec900db..0000000 --- a/chrome/browser/resources/chromeos/login/apps_menu.js +++ /dev/null
@@ -1,170 +0,0 @@ -// Copyright 2013 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. - -/** - * @fileoverview Kiosk apps menu implementation. - */ - -cr.define('login', function() { - 'use strict'; - - var Menu = cr.ui.Menu; - var MenuButton = cr.ui.MenuButton; - - /** - * Creates apps menu button. - * @constructor - * @extends {cr.ui.MenuButton} - */ - var AppsMenuButton = cr.ui.define('button'); - - AppsMenuButton.prototype = { - __proto__: MenuButton.prototype, - - /** - * Flag of whether to rebuild the menu. - * @type {boolean} - * @private - */ - needsRebuild_: true, - - /** - * Array to hold apps info. - * @type {Array} - */ - data_: null, - get data() { - return this.data_; - }, - set data(data) { - this.data_ = data; - this.needsRebuild_ = true; - }, - - /** @override */ - decorate: function() { - MenuButton.prototype.decorate.call(this); - this.menu = new Menu; - cr.ui.decorate(this.menu, Menu); - document.body.appendChild(this.menu); - - this.anchorType = cr.ui.AnchorType.ABOVE; - chrome.send('initializeKioskApps'); - }, - - /** @override */ - showMenu: function(shouldSetFocus) { - if (this.needsRebuild_) { - this.menu.textContent = ''; - this.data_.forEach(this.addItem_, this); - this.needsRebuild_ = false; - } - - if (this.data.length > 0) - MenuButton.prototype.showMenu.apply(this, arguments); - }, - - /** - * Invoked when apps menu becomes visible. - */ - didShow: function() { - window.setTimeout(function() { - if (!$('apps-header-bar-item').hidden) - chrome.send('checkKioskAppLaunchError'); - }, 500); - }, - - findAndRunAppForTesting: function(id, opt_diagnostic_mode) { - for (var i = 0; i < this.data.length; i++) { - if (this.data[i].id == id) { - this.launchApp_(this.data[i], !!opt_diagnostic_mode); - break; - } - } - }, - - /** - * Launch the app. If |diagnosticMode| is true, ask user to confirm. - * @param {Object} app App data. - * @param {boolean} diagnosticMode Whether to run the app in diagnostic - * mode. - */ - launchApp_: function(app, diagnosticMode) { - if (app.isAndroidApp) { - chrome.send('launchArcKioskApp', [app.account_email]); - return; - } - if (!diagnosticMode) { - chrome.send('launchKioskApp', [app.id, false]); - return; - } - - if (!this.confirmDiagnosticMode_) { - this.confirmDiagnosticMode_ = - new cr.ui.dialogs.ConfirmDialog(document.body); - this.confirmDiagnosticMode_.setOkLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeYes')); - this.confirmDiagnosticMode_.setCancelLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeNo')); - } - - this.confirmDiagnosticMode_.show( - loadTimeData.getStringF( - 'confirmKioskAppDiagnosticModeFormat', app.label), - function() { - chrome.send('launchKioskApp', [app.id, true]); - }); - }, - - /** - * Adds an app to the menu. - * @param {Object} app An app info object. - * @private - */ - addItem_: function(app) { - var menuItem = this.menu.addMenuItem(app); - menuItem.classList.add('apps-menu-item'); - menuItem.addEventListener('activate', function(e) { - var diagnosticMode = e.originalEvent && e.originalEvent.ctrlKey; - this.launchApp_(app, diagnosticMode); - }.bind(this)); - } - }; - - /** - * Sets apps to be displayed in the apps menu. - * @param {!Array<!Object>} apps An array of app info objects. - */ - AppsMenuButton.setApps = function(apps) { - $('show-apps-button').data = apps; - $('login-header-bar').hasApps = - apps.length > 0 || loadTimeData.getBoolean('kioskAppHasLaunchError'); - chrome.send('kioskAppsLoaded'); - }; - - /** - * Shows the given error message. - * @param {!string} message Error message to show. - */ - AppsMenuButton.showError = function(message) { - /** @const */ var BUBBLE_OFFSET = 25; - /** @const */ var BUBBLE_PADDING = 12; - $('bubble').showTextForElement( - $('show-apps-button'), message, cr.ui.Bubble.Attachment.TOP, - BUBBLE_OFFSET, BUBBLE_PADDING); - }; - - - /** - * Runs app with a given id from the list of loaded apps. - * @param {!string} id of an app to run. - * @param {boolean=} opt_diagnostic_mode Whether to run the app in diagnostic - * mode. Default is false. - */ - AppsMenuButton.runAppForTesting = function(id, opt_diagnostic_mode) { - $('show-apps-button').findAndRunAppForTesting(id, opt_diagnostic_mode); - }; - - return {AppsMenuButton: AppsMenuButton}; -});
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js index a143d1d..0636594 100644 --- a/chrome/browser/resources/chromeos/login/cr_ui.js +++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -81,34 +81,10 @@ Oobe.showOobeUI = function(showOobe) { if (showOobe) { document.body.classList.add('oobe-display'); - - // Callback to animate the header bar in. - var showHeaderBar = function() { - login.HeaderBar.animateIn(false, function() { - chrome.send('headerBarVisible'); - }); - }; - // Start asynchronously so the OOBE welcome screen comes in first. - window.setTimeout(showHeaderBar, HEADER_BAR_DELAY_MS); } else { document.body.classList.remove('oobe-display'); Oobe.getInstance().prepareForLoginDisplay_(); - // Ensure header bar is visible when switching to Login UI from oobe. - if (Oobe.getInstance().displayType == DISPLAY_TYPE.OOBE) - login.HeaderBar.animateIn(true); } - - Oobe.getInstance().headerHidden = false; - }; - - /** - * When |showShutdown| is set to "true", the shutdown button is shown and the - * reboot button hidden. If set to "false", the reboot button is visible and - * the shutdown button hidden. - */ - Oobe.showShutdown = function(showShutdown) { - $('login-header-bar').showShutdownButton = showShutdown; - $('login-header-bar').showRebootButton = !showShutdown; }; /** @@ -381,13 +357,6 @@ }; /** - * Shows/hides login UI control bar with buttons like [Shut down]. - */ - Oobe.showControlBar = function(show) { - Oobe.getInstance().headerHidden = !show; - }; - - /** * Changes some UI which depends on the virtual keyboard being shown/hidden. */ Oobe.setVirtualKeyboardShown = function(shown) {
diff --git a/chrome/browser/resources/chromeos/login/discover/discover_app.js b/chrome/browser/resources/chromeos/login/discover/discover_app.js index 7e634d3..2dc0cd6 100644 --- a/chrome/browser/resources/chromeos/login/discover/discover_app.js +++ b/chrome/browser/resources/chromeos/login/discover/discover_app.js
@@ -33,7 +33,6 @@ setClientAreaSize: function(data) {}, showAPIKeysNotice: function(data) {}, showOobeUI: function(data) {}, - showShutdown: function(data) {}, showVersion: function(data) {}, updateDeviceRequisition: function(data) {}, updateOobeConfiguration: function(data) {},
diff --git a/chrome/browser/resources/chromeos/login/encryption_migration.css b/chrome/browser/resources/chromeos/login/encryption_migration.css index 1acb3be..df67332 100644 --- a/chrome/browser/resources/chromeos/login/encryption_migration.css +++ b/chrome/browser/resources/chromeos/login/encryption_migration.css
@@ -4,7 +4,7 @@ oobe-dialog { height: 640px; - max-height: calc(100vh - 47px); /* Subtracting #login-header-bar's height. */ + max-height: calc(100vh - 56px); /* Subtracting LoginShelfView's height. */ max-width: 100vw; min-height: 0 !important; /* Making <oobe-dialog> shrinkable. */ min-width: 0 !important; /* Making <oobe-dialog> shrinkable. */
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.css b/chrome/browser/resources/chromeos/login/md_header_bar.css deleted file mode 100644 index 73bfaf3..0000000 --- a/chrome/browser/resources/chromeos/login/md_header_bar.css +++ /dev/null
@@ -1,132 +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. */ - -#login-header-bar { - bottom: 0; - left: 0; - min-height: 34px; /* Should be consistent with .header-bar-item's height. */ - padding-bottom: 6px; - position: absolute; - right: 0; -} - -#login-header-bar { - padding-top: 7px; -} - -#login-header-bar.translucent-background { - background-color: rgba(0, 0, 0, 0.9); -} - -html[screen=lock] .login-header-bar-hidden, -html[screen=oobe] .login-header-bar-hidden { - opacity: 0; -} - -html[screen=lock] .login-header-bar-animate-fast, -html[screen=oobe] .login-header-bar-animate-fast { - transition: opacity 200ms ease-out; -} - -html[screen=lock] .login-header-bar-animate-slow, -html[screen=oobe] .login-header-bar-animate-slow { - transition: opacity 2s ease-out; -} - -#login-header-bar button, -#login-header-bar button:active, -#login-header-bar button:focus, -#login-header-bar button:hover { - background: transparent none; - box-shadow: none; - cursor: pointer; - height: 34px; - margin: 0; - min-width: 0; - opacity: 0.6; - padding: 5px 8px; - vertical-align: middle; -} - -#login-header-bar button { - color: white !important; -} - -html[full-screen-dialog] #login-header-bar button { - color: var(--google-grey-600) !important; -} - -#login-header-bar hd-iron-icon { - --iron-icon-fill-color: white; - --iron-icon-height: 20px; - --iron-icon-width: 20px; - padding-inline-end: 8px; -} - -html[full-screen-dialog] #login-header-bar hd-iron-icon { - --iron-icon-fill-color: var(--google-grey-600); -} - -#login-header-bar button:not(.button-restricted), -#login-header-bar button:active:not(.button-restricted), -#login-header-bar button:focus:not(.button-restricted), -#login-header-bar button:hover:not(.button-restricted) { - opacity: 1 !important; -} - -.header-bar-item { - height: 34px; - z-index: 3; /* Stays above the scrollable container. */ -} - -.add-supervised-user-menu { - display: none; -} - -#more-settings-header-bar-item.active button.add-supervised-user-menu { - background-color: white; - border: 1px solid lightgray; - border-radius: 2px; - bottom: 0; - color: black !important; - display: block; - font-size: 13px; - height: auto; - min-height: 34px; - padding: 0 16px; - position: absolute; - text-align: center; - white-space: nowrap; - z-index: 3; -} - -#more-settings-header-bar-item.active button.add-supervised-user-menu:focus { - font-weight: bold; -} - -html[dir=rtl] .header-bar-item { - background-position: right center; -} - -#login-header-bar #shutdown-button, -#login-header-bar #restart-button, -#login-header-bar #add-user-button, -#login-header-bar #guest-user-button, -#login-header-bar #cancel-multiple-sign-in-button { - padding: 0 12px; -} - -#login-header-bar #more-settings-button { - padding: 0 10px 0 18px; -} - -#login-header-bar #more-settings-header-bar-item { - position: relative; -} - -.button-restricted { - border: 1px solid transparent; - color: white !important; - opacity: 0.4 !important; -}
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.html b/chrome/browser/resources/chromeos/login/md_header_bar.html deleted file mode 100644 index 4b17f48..0000000 --- a/chrome/browser/resources/chromeos/login/md_header_bar.html +++ /dev/null
@@ -1,162 +0,0 @@ -<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> - -<iron-iconset-svg name="header-bar-10" size="10"> - <svg> - <defs> - <g id="show-apps" fill-rule="evenodd"> - <path d="M1,3 L3,3 L3,1 L1,1 L1,3 Z M4,9 L6,9 L6,7 L4,7 L4,9 Z M1,9 L3,9 L3,7 L1,7 L1,9 Z M1,6 L3,6 L3,4 L1,4 L1,6 Z M4,6 L6,6 L6,4 L4,4 L4,6 Z M7,1 L7,3 L9,3 L9,1 L7,1 Z M4,3 L6,3 L6,1 L4,1 L4,3 Z M7,6 L9,6 L9,4 L7,4 L7,6 Z M7,9 L9,9 L9,7 L7,7 L7,9 Z"> - </path> - </g> - </defs> - </svg> -</iron-iconset-svg> - -<iron-iconset-svg name="header-bar-20" size="20"> - <svg> - <defs> - <g id="shutdown" fill-rule="evenodd"> - <path d="M10.834 2.5H9.167v8.334h1.667V2.5zm4.025 1.808l-1.185 1.184C14.99 6.55 15.834 8.175 15.834 10c0 3.225-2.61 5.834-5.834 5.834-3.225 0-5.833-2.61-5.833-5.834 0-1.825.842-3.45 2.15-4.516L5.14 4.31C3.526 5.683 2.5 7.716 2.5 9.998c0 4.141 3.358 7.5 7.5 7.5 4.141 0 7.5-3.358 7.5-7.5 0-2.284-1.025-4.316-2.642-5.69z"> - </path> - </g> - <g id="show-apps" fill-rule="evenodd"> - <path d="M3,7 L7,7 L7,3 L3,3 L3,7 Z M8,17 L12,17 L12,13 L8,13 L8,17 Z M3,17 L7,17 L7,13 L3,13 L3,17 Z M3,12 L7,12 L7,8 L3,8 L3,12 Z M8,12 L12,12 L12,8 L8,8 L8,12 Z M13,3 L13,7 L17,7 L17,3 L13,3 Z M8,7 L12,7 L12,3 L8,3 L8,7 Z M13,12 L17,12 L17,8 L13,8 L13,12 Z M13,17 L17,17 L17,13 L13,13 L13,17 Z"> - </path> - </g> - <g id="browse-as-guest" fill-rule="evenodd"> - <path d="M10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm0 2.4c1.328 0 2.4 1.072 2.4 2.4 0 1.328-1.072 2.4-2.4 2.4-1.328 0-2.4-1.072-2.4-2.4 0-1.328 1.072-2.4 2.4-2.4zm-5 8.79c.025-1.74 3.334-2.69 5-2.69 1.66 0 4.975.952 5 2.69-1.075 1.693-2.916 2.81-5 2.81-2.083 0-3.925-1.117-5-2.81z"> - </path> - </g> - <g id="add-person" fill-rule="evenodd"> - <path d="M7.6 9.8c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm4.8 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zM10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm0 14.4c-3.528 0-6.4-2.872-6.4-6.4 0-.232.016-.464.04-.688 1.888-.84 3.384-2.384 4.168-4.296C9.256 7.064 11.64 8.4 14.336 8.4c.624 0 1.224-.072 1.8-.208.168.568.264 1.176.264 1.808 0 3.528-2.872 6.4-6.4 6.4z"> - </path> - </g> - <g id="more-settings" fill-rule="evenodd"> - <path d="M10 6c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm0 6c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm0 6c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z"> - </path> - </g> - <g id="sign-out" fill-rule="evenodd"> - <path d="M9.5 15l5-5-5-5L8 6.5 10.5 9H2v2h8.5L8 13.5 9.5 15zM4 2c-.987 0-2 1.022-2 2v3.067h2V4h12v12H4v-3H2v3c0 .978 1.013 2 2 2h12c.978 0 2-1.022 2-2V4c0-1-1.022-2-2-2H4z"> - </path> - </g> - <g id="cancel" fill-rule="evenodd"> - <path d="M9.72 5.89c-2.2 0-4.194.88-5.73 2.31L1 5v8h7.474L5.468 9.782c1.154-1.03 2.624-1.67 4.252-1.67 2.94 0 5.44 2.052 6.312 4.888L18 12.307C16.846 8.582 13.582 5.89 9.72 5.89z"> - </path> - </g> - </defs> - </svg> -</iron-iconset-svg> - -<iron-iconset-svg name="header-bar-40" size="40"> - <svg> - <defs> - <g id="shutdown" fill-rule="evenodd"> - <path d="M21.667 5h-3.334v16.667h3.334V5zm8.05 3.617l-2.367 2.366C29.983 13.1 31.667 16.35 31.667 20c0 6.45-5.217 11.667-11.667 11.667S8.333 26.45 8.333 20c0-3.65 1.684-6.9 4.3-9.033l-2.35-2.35C7.05 11.367 5 15.433 5 20c0 8.283 6.717 15 15 15 8.283 0 15-6.717 15-15 0-4.567-2.05-8.633-5.283-11.383z"> - </path> - </g> - <g id="browse-as-guest" fill-rule="evenodd"> - <path d="M20 4C11.168 4 4 11.168 4 20s7.168 16 16 16 16-7.168 16-16S28.832 4 20 4zm0 4.8c2.656 0 4.8 2.144 4.8 4.8 0 2.656-2.144 4.8-4.8 4.8-2.656 0-4.8-2.144-4.8-4.8 0-2.656 2.144-4.8 4.8-4.8zM10 26.378C10.05 22.903 16.667 21 20 21c3.317 0 9.95 1.903 10 5.378C27.85 29.765 24.167 32 20 32s-7.85-2.235-10-5.622z"> - </path> - </g> - <g id="add-person" fill-rule="evenodd"> - <path d="M15.2 19.6c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2zm9.6 0c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2zM20 4C11.168 4 4 11.168 4 20s7.168 16 16 16 16-7.168 16-16S28.832 4 20 4zm0 28.8c-7.056 0-12.8-5.744-12.8-12.8 0-.464.032-.928.08-1.376 3.776-1.68 6.768-4.768 8.336-8.592 2.896 4.096 7.664 6.768 13.056 6.768 1.248 0 2.448-.144 3.6-.416.336 1.136.528 2.352.528 3.616 0 7.056-5.744 12.8-12.8 12.8z"> - </path> - </g> - <g id="more-settings" fill-rule="evenodd"> - <path d="M20 14c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 9c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 9c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3z"> - </path> - </g> - <g id="sign-out" fill-rule="evenodd"> - <path d="M19.48 29L28 20.5 19.48 12 17 14.5l4.5 4.5H5v3h16.5L17 26.5l2.48 2.5zM8.334 5C6.483 5 5 6.5 5 8.333V15h3V8.006h24v24.02H8V26H5v5.667C5 33.5 6.483 35 8.333 35h23.334C33.5 35 35 33.5 35 31.667V8.333C35 6.5 33.5 5 31.667 5H8.333z"> - </path> - </g> - <g id="cancel" fill-rule="evenodd"> - <path d="M20.44 12.667c-4.4 0-8.388 1.65-11.46 4.333L3 11v15h14.95l-6.014-6.033c2.31-1.934 5.25-3.134 8.504-3.134 5.88 0 10.88 3.85 12.624 9.167L37 24.7c-2.31-6.983-8.836-12.033-16.56-12.033z"> - </path> - </g> - </defs> - </svg> -</iron-iconset-svg> - -<link rel="stylesheet" href="oobe_flex_layout.css"> -<div id="login-header-bar" hidden - class="login-header-bar-hidden layout horizontal"> - <div id="shutdown-header-bar-item" class="header-bar-item"> - <button id="shutdown-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:shutdown" icon2x="header-bar-40:shutdown"> - </hd-iron-icon> - <div i18n-content="shutDown"></div> - </div> - </button> - </div> - <div id="restart-header-bar-item" class="header-bar-item"> - <button id="restart-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:shutdown" icon2x="header-bar-40:shutdown"> - </hd-iron-icon> - <div i18n-content="shutDown"></div> - </div> - </button> - </div> - <div id="apps-header-bar-item" class="header-bar-item" hidden> - <button id="show-apps-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-10:show-apps" icon2x="header-bar-20:show-apps"> - </hd-iron-icon> - <div i18n-content="showApps"></div> - </div> - </button> - </div> - <div id="guest-user-header-bar-item" class="header-bar-item" hidden> - <button id="guest-user-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:browse-as-guest" icon2x="header-bar-40:browse-as-guest"> - </hd-iron-icon> - <div i18n-content="browseAsGuest"></div> - </div> - </button> - </div> - <div id="add-user-header-bar-item" class="header-bar-item" hidden> - <button id="add-user-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:add-person" icon2x="header-bar-40:add-person"> - </hd-iron-icon> - <div i18n-content="addUser"></div> - </div> - </button> - </div> - <div id="more-settings-header-bar-item" class="header-bar-item"> - <button id="more-settings-button" class="custom-appearance layout vertical" - i18n-values="aria-label:moreOptions"> - <hd-iron-icon - icon1x="header-bar-20:more-settings" icon2x="header-bar-40:more-settings"> - </hd-iron-icon> - </button> - </div> - <div id="sign-out-user-item" class="header-bar-item" hidden> - <button id="sign-out-user-button" class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:sign-out" icon2x="header-bar-40:sign-out"> - </hd-iron-icon> - <div i18n-content="signOutUser"></div> - </div> - </button> - </div> - <div id="cancel-multiple-sign-in-item" class="header-bar-item" hidden> - <button id="cancel-multiple-sign-in-button" - class="custom-appearance layout vertical"> - <div class="flex layout horizontal center"> - <hd-iron-icon - icon1x="header-bar-20:cancel" icon2x="header-bar-40:cancel"> - </hd-iron-icon> - <div i18n-content="cancel"></div> - </div> - </button> - </div> -</div>
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.js b/chrome/browser/resources/chromeos/login/md_header_bar.js deleted file mode 100644 index a357252c..0000000 --- a/chrome/browser/resources/chromeos/login/md_header_bar.js +++ /dev/null
@@ -1,355 +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. - -/** - * @fileoverview Login UI header bar implementation. - */ - -cr.define('login', function() { - /** - * Creates a header bar element. - * - * @constructor - * @extends {HTMLDivElement} - */ - var HeaderBar = cr.ui.define('div'); - - HeaderBar.prototype = { - __proto__: HTMLDivElement.prototype, - - // Whether guest button should be shown when header bar is in normal mode. - showGuest_: false, - - // Whether the reboot button should be shown the when header bar is in - // normal mode. - showReboot_: false, - - // Whether the shutdown button should be shown when the header bar is in - // normal mode. - showShutdown_: true, - - // Current UI state of the sign-in screen. - signinUIState_: SIGNIN_UI_STATE.HIDDEN, - - // Whether to show kiosk apps menu. - hasApps_: false, - - /** @override */ - decorate: function() { - document.addEventListener('click', this.handleClick_.bind(this)); - $('shutdown-header-bar-item') - .addEventListener('click', this.handleShutdownClick_.bind(this)); - $('shutdown-button') - .addEventListener('click', this.handleShutdownClick_.bind(this)); - $('restart-header-bar-item') - .addEventListener('click', this.handleShutdownClick_.bind(this)); - $('restart-button') - .addEventListener('click', this.handleShutdownClick_.bind(this)); - $('add-user-button').addEventListener('click', this.handleAddUserClick_); - $('more-settings-button') - .addEventListener('click', this.handleMoreSettingsClick_.bind(this)); - $('guest-user-header-bar-item') - .addEventListener('click', this.handleGuestClick_); - $('guest-user-button').addEventListener('click', this.handleGuestClick_); - $('sign-out-user-button') - .addEventListener('click', this.handleSignoutClick_.bind(this)); - $('cancel-multiple-sign-in-button') - .addEventListener('click', this.handleCancelMultipleSignInClick_); - if (Oobe.getInstance().displayType == DISPLAY_TYPE.LOGIN || - Oobe.getInstance().displayType == DISPLAY_TYPE.OOBE) { - if (Oobe.getInstance().newKioskUI) - chrome.send('initializeKioskApps'); - else - login.AppsMenuButton.decorate($('show-apps-button')); - } - this.updateUI_(); - }, - - /** - * Tab index value for all button elements. - * - * @type {number} - */ - set buttonsTabIndex(tabIndex) { - var buttons = this.getElementsByTagName('button'); - for (var i = 0, button; button = buttons[i]; ++i) { - button.tabIndex = tabIndex; - } - }, - - /** - * Disables the header bar and all of its elements. - * - * @type {boolean} - */ - set disabled(value) { - var buttons = this.getElementsByTagName('button'); - for (var i = 0, button; button = buttons[i]; ++i) - if (!button.classList.contains('button-restricted')) - button.disabled = value; - }, - - get getMoreSettingsMenu() { - return $('more-settings-header-bar-item'); - }, - - /** - * Whether action box button is in active state. - * @type {boolean} - */ - get isMoreSettingsActive() { - return this.getMoreSettingsMenu.classList.contains('active'); - }, - set isMoreSettingsActive(active) { - if (active == this.isMoreSettingsActive) - return; - this.getMoreSettingsMenu.classList.toggle('active', active); - $('more-settings-button').tabIndex = active ? -1 : 4; - }, - - /** - * Add user button click handler. - * - * @private - */ - handleAddUserClick_: function(e) { - Oobe.showSigninUI(); - // Prevent further propagation of click event. Otherwise, the click event - // handler of document object will set wallpaper to user's wallpaper when - // there is only one existing user. See http://crbug.com/166477 - e.stopPropagation(); - }, - - handleMoreSettingsClick_: function(e) { - this.isMoreSettingsActive = !this.isMoreSettingsActive; - e.stopPropagation(); - }, - - handleClick_: function(e) { - this.isMoreSettingsActive = false; - }, - - /** - * Cancel add user button click handler. - * - * @private - */ - handleCancelAddUserClick_: function(e) { - // Let screen handle cancel itself if that is capable of doing so. - if (Oobe.getInstance().currentScreen && - Oobe.getInstance().currentScreen.cancel) { - Oobe.getInstance().currentScreen.cancel(); - return; - } - - Oobe.showUserPods(); - }, - - /** - * Guest button click handler. - * - * @private - */ - handleGuestClick_: function(e) { - Oobe.disableSigninUI(); - chrome.send('launchIncognito'); - e.stopPropagation(); - }, - - /** - * Sign out button click handler. - * - * @private - */ - handleSignoutClick_: function(e) { - this.disabled = true; - - chrome.send('signOutUser'); - e.stopPropagation(); - }, - - /** - * Shutdown button click handler. - * - * @private - */ - handleShutdownClick_: function(e) { - chrome.send('shutdownSystem'); - e.stopPropagation(); - }, - - /** - * Cancel user adding button handler. - * - * @private - */ - handleCancelMultipleSignInClick_: function(e) { - chrome.send('cancelUserAdding'); - e.stopPropagation(); - }, - - /** - * If true then "Browse as Guest" button is shown. - * - * @type {boolean} - */ - set showGuestButton(value) { - this.showGuest_ = value; - this.updateUI_(); - }, - - /** - * If true the "Restart" button is shown. - * - * @type {boolean} - */ - set showRebootButton(value) { - this.showReboot_ = value; - this.updateUI_(); - }, - - /** - * If true the "Shutdown" button is shown. - * - * @type {boolean} - */ - set showShutdownButton(value) { - this.showShutdown_ = value; - this.updateUI_(); - }, - - /** - * Current header bar UI / sign in state. - * - * @type {number} state Current state of the sign-in screen (see - * SIGNIN_UI_STATE). - */ - get signinUIState() { - return this.signinUIState_; - }, - set signinUIState(state) { - this.signinUIState_ = state; - this.updateUI_(); - }, - - /** - * Update whether there are kiosk apps. - * - * @type {boolean} - */ - set hasApps(value) { - this.hasApps_ = value; - this.updateUI_(); - }, - - /** - * Updates visibility state of action buttons. - * - * @private - */ - updateUI_: function() { - var gaiaIsActive = (this.signinUIState_ == SIGNIN_UI_STATE.GAIA_SIGNIN); - var enrollmentIsActive = - (this.signinUIState_ == SIGNIN_UI_STATE.ENROLLMENT); - var accountPickerIsActive = - (this.signinUIState_ == SIGNIN_UI_STATE.ACCOUNT_PICKER); - var wrongHWIDWarningIsActive = - (this.signinUIState_ == SIGNIN_UI_STATE.WRONG_HWID_WARNING); - var isSamlPasswordConfirm = - (this.signinUIState_ == SIGNIN_UI_STATE.SAML_PASSWORD_CONFIRM); - var isPasswordChangedUI = - (this.signinUIState_ == SIGNIN_UI_STATE.PASSWORD_CHANGED); - var isMultiProfilesUI = - (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING); - var isLockScreen = (Oobe.getInstance().displayType == DISPLAY_TYPE.LOCK); - var errorScreenIsActive = (this.signinUIState_ == SIGNIN_UI_STATE.ERROR); - - $('add-user-button').hidden = !accountPickerIsActive || - isMultiProfilesUI || isLockScreen || errorScreenIsActive; - $('more-settings-header-bar-item').hidden = true; - $('guest-user-header-bar-item').hidden = !this.showGuest_ || - isLockScreen || wrongHWIDWarningIsActive || isSamlPasswordConfirm || - isMultiProfilesUI || (gaiaIsActive && $('gaia-signin').closable) || - (enrollmentIsActive && !$('oauth-enrollment').isAtTheBeginning()) || - (gaiaIsActive && !$('gaia-signin').isAtTheBeginning()); - $('restart-header-bar-item').hidden = !this.showReboot_; - $('shutdown-header-bar-item').hidden = !this.showShutdown_; - $('sign-out-user-item').hidden = !isLockScreen; - - $('add-user-header-bar-item').hidden = $('add-user-button').hidden; - $('apps-header-bar-item').hidden = - !this.hasApps_ || (!gaiaIsActive && !accountPickerIsActive); - $('cancel-multiple-sign-in-item').hidden = !isMultiProfilesUI; - - if (!Oobe.getInstance().newKioskUI) { - if (!$('apps-header-bar-item').hidden) - $('show-apps-button').didShow(); - } - }, - - /** - * Animates Header bar to hide from the screen. - * - * @param {function()} callback will be called once animation is finished. - */ - animateOut: function(callback) { - var launcher = this; - launcher.addEventListener('transitionend', function f(e) { - launcher.removeEventListener('transitionend', f); - callback(); - }); - // Guard timer for 2 seconds + 200 ms + epsilon. - ensureTransitionEndEvent(launcher, 2250); - - this.classList.remove('login-header-bar-animate-slow'); - this.classList.add('login-header-bar-animate-fast'); - this.classList.add('login-header-bar-hidden'); - }, - - /** - * Animates Header bar to appear on the screen. - * - * @param {boolean} fast Whether the animation should complete quickly or - * slowly. - * @param {function()} callback will be called once animation is finished. - */ - animateIn: function(fast, callback) { - if (callback) { - var launcher = this; - launcher.addEventListener('transitionend', function f(e) { - launcher.removeEventListener('transitionend', f); - callback(); - }); - // Guard timer for 2 seconds + 200 ms + epsilon. - ensureTransitionEndEvent(launcher, 2250); - } - - if (fast) { - this.classList.remove('login-header-bar-animate-slow'); - this.classList.add('login-header-bar-animate-fast'); - } else { - this.classList.remove('login-header-bar-animate-fast'); - this.classList.add('login-header-bar-animate-slow'); - } - - this.classList.remove('login-header-bar-hidden'); - }, - }; - - /** - * Convenience wrapper of animateOut. - */ - HeaderBar.animateOut = function(callback) { - $('login-header-bar').animateOut(callback); - }; - - /** - * Convenience wrapper of animateIn. - */ - HeaderBar.animateIn = function(fast, callback) { - $('login-header-bar').animateIn(fast, callback); - }; - - return {HeaderBar: HeaderBar}; -});
diff --git a/chrome/browser/resources/chromeos/login/md_login.html b/chrome/browser/resources/chromeos/login/md_login.html index 9ae8e23..8154b02e 100644 --- a/chrome/browser/resources/chromeos/login/md_login.html +++ b/chrome/browser/resources/chromeos/login/md_login.html
@@ -21,7 +21,6 @@ <link rel="stylesheet" href="chrome://resources/css/widgets.css"> <link rel="stylesheet" href="apps_menu.css"> <link rel="stylesheet" href="../../../../../ui/login/bubble.css"> -<link rel="stylesheet" href="md_header_bar.css"> <link rel="stylesheet" href="md_top_header_bar.css"> <link rel="stylesheet" href="../../../../../ui/login/oobe.css"> <link rel="stylesheet" href="oobe_popup_overlay.css">
diff --git a/chrome/browser/resources/chromeos/login/md_login.js b/chrome/browser/resources/chromeos/login/md_login.js index bf1f578..a03c337 100644 --- a/chrome/browser/resources/chromeos/login/md_login.js +++ b/chrome/browser/resources/chromeos/login/md_login.js
@@ -9,10 +9,8 @@ // <include src="test_util.js"> // <include src="../../../../../ui/login/screen.js"> // <include src="screen_context.js"> -// <include src="apps_menu.js"> // <include src="../../../../../ui/login/bubble.js"> // <include src="../../../../../ui/login/display_manager.js"> -// <include src="md_header_bar.js"> // <include src="demo_mode_test_helper.js"> // <include @@ -113,7 +111,6 @@ $('bubble-persistent').hideOnKeyPress = false; cr.ui.Bubble.decorate($('bubble')); - login.HeaderBar.decorate($('login-header-bar')); chrome.send('screenStateInitialize');
diff --git a/chrome/browser/resources/chromeos/login/md_screen_container.html b/chrome/browser/resources/chromeos/login/md_screen_container.html index 069b4e1..3831f8b6 100644 --- a/chrome/browser/resources/chromeos/login/md_screen_container.html +++ b/chrome/browser/resources/chromeos/login/md_screen_container.html
@@ -17,6 +17,5 @@ <div id="bubble-persistent" class="bubble faded" hidden></div> <div id="bubble" class="bubble faded" hidden></div> <include src="md_top_header_bar.html"> -<include src="md_header_bar.html"> <include src="../../../../../ui/login/account_picker/chromeos_user_pod_template.html"> <include src="oobe_screen_reset_confirmation_overlay.html">
diff --git a/chrome/browser/resources/chromeos/login/oobe.html b/chrome/browser/resources/chromeos/login/oobe.html index f7c3c386..8ef0b36 100644 --- a/chrome/browser/resources/chromeos/login/oobe.html +++ b/chrome/browser/resources/chromeos/login/oobe.html
@@ -23,7 +23,6 @@ <link rel="stylesheet" href="apps_menu.css"> <link rel="stylesheet" href="../../../../../ui/login/bubble.css"> -<link rel="stylesheet" href="md_header_bar.css"> <link rel="stylesheet" href="md_top_header_bar.css"> <link rel="stylesheet" href="../../../../../ui/login/oobe.css"> <link rel="stylesheet" href="oobe_popup_overlay.css">
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index 5bebe511e..dfe9328 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -10,10 +10,8 @@ // <include src="test_util.js"> // <include src="../../../../../ui/login/screen.js"> // <include src="screen_context.js"> -// <include src="apps_menu.js"> // <include src="../../../../../ui/login/bubble.js"> // <include src="../../../../../ui/login/display_manager.js"> -// <include src="md_header_bar.js"> // <include src="demo_mode_test_helper.js"> // <include @@ -142,7 +140,6 @@ $('bubble-persistent').hideOnKeyPress = false; cr.ui.Bubble.decorate($('bubble')); - login.HeaderBar.decorate($('login-header-bar')); chrome.send('screenStateInitialize'); },
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.js b/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.js index 2cfaebc0..818ec10 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.js
@@ -16,7 +16,6 @@ /** @Override */ onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; $('assistant-optin-flow-card').onShow(); },
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_supervision_transition.js b/chrome/browser/resources/chromeos/login/oobe_screen_supervision_transition.js index 6ed2a1a..efe6064 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_supervision_transition.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_supervision_transition.js
@@ -16,7 +16,6 @@ /** @override */ onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; $('supervision-transition-md') .setIsRemovingSupervision( data['isRemovingSupervision'] ? true : false);
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js b/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js index bd7a56e..91f6f22 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js
@@ -108,13 +108,5 @@ return $('tos-accept-button').disabled ? $('tos-back-button') : $('tos-accept-button'); }, - - /** - * Event handler that is invoked just before the screen is shown. - * @param {object} data Screen init payload. - */ - onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; - } }; });
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js index 01e59d0..5ad495a7 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
@@ -82,7 +82,6 @@ * @param {object} data Screen init payload. */ onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; this.loading = true; chrome.send('onUserImageScreenShown'); },
diff --git a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js index f0c9849..0bcd53fd 100644 --- a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js +++ b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js
@@ -57,7 +57,6 @@ onBeforeShow: function(data) { // Active Directory password change screen is similar to Active // Directory login screen. So we restore bottom bar controls. - Oobe.getInstance().headerHidden = false; this.adPasswordChanged_.reset(); if ('username' in data) this.adPasswordChanged_.username = data.username;
diff --git a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js index 0e714c6..cbd08dd 100644 --- a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js +++ b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js
@@ -53,7 +53,6 @@ $('splash-shortcut-info').hidden = !data['shortcutEnabled']; - Oobe.getInstance().headerHidden = true; Oobe.getInstance().solidBackground = true; },
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js b/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js index d7e1284..d8e66b0 100644 --- a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js +++ b/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js
@@ -22,7 +22,6 @@ onBeforeShow: function(data) { this.updateApp(data['appInfo']); - Oobe.getInstance().headerHidden = true; Oobe.getInstance().solidBackground = true; },
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js index 7808f0c..0039697 100644 --- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js +++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
@@ -602,8 +602,6 @@ onBeforeShow: function(data) { this.setLearnMoreHandlers_(); - Oobe.getInstance().headerHidden = true; - this.hideOverlay(); // ToS content may be loaded before the page is shown. In that case, // height of ToS webview is not correctly calculated. Recalculate the
diff --git a/chrome/browser/resources/chromeos/login/screen_discover.js b/chrome/browser/resources/chromeos/login/screen_discover.js index 9b70d40..48c5f63 100644 --- a/chrome/browser/resources/chromeos/login/screen_discover.js +++ b/chrome/browser/resources/chromeos/login/screen_discover.js
@@ -20,7 +20,6 @@ * @param {object} data Screen init payload. */ onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; $('discover-impl').addEventListener('discover-done', function() { chrome.send('login.DiscoverScreen.userActed', ['finished']); });
diff --git a/chrome/browser/resources/chromeos/login/screen_encryption_migration.js b/chrome/browser/resources/chromeos/login/screen_encryption_migration.js index 9a66670..1a1a8ad7 100644 --- a/chrome/browser/resources/chromeos/login/screen_encryption_migration.js +++ b/chrome/browser/resources/chromeos/login/screen_encryption_migration.js
@@ -65,11 +65,6 @@ */ setUIState: function(state) { $('encryption-migration-element').uiState = state; - - // TODO(qnnguyen): Hide the views login shelf "Shutdown" button during - // migration. - $('login-header-bar').showShutdownButton = - state != EncryptionMigrationUIState.MIGRATING; }, /**
diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.js b/chrome/browser/resources/chromeos/login/screen_error_message.js index b5e5b282..178d9ad5 100644 --- a/chrome/browser/resources/chromeos/login/screen_error_message.js +++ b/chrome/browser/resources/chromeos/login/screen_error_message.js
@@ -283,12 +283,6 @@ this.classList.remove(this.ui_state); this.ui_state = ui_state; this.classList.add(this.ui_state); - - if (ui_state == ERROR_SCREEN_UI_STATE.LOCAL_STATE_ERROR) { - // Hide header bar and progress dots, because there are no way - // from the error screen about broken local state. - Oobe.getInstance().headerHidden = true; - } this.onContentChange_(); },
diff --git a/chrome/browser/resources/chromeos/login/screen_fatal_error.js b/chrome/browser/resources/chromeos/login/screen_fatal_error.js index 56f1572..0a0f2d77 100644 --- a/chrome/browser/resources/chromeos/login/screen_fatal_error.js +++ b/chrome/browser/resources/chromeos/login/screen_fatal_error.js
@@ -33,17 +33,6 @@ return $('fatal-error-card').submitButton; }, - /** @override */ - onBeforeShow: function() { - this.savedUIStates_.headerHidden = Oobe.getInstance().headerHidden; - Oobe.getInstance().headerHidden = true; - }, - - /** @override */ - onBeforeHide: function() { - Oobe.getInstance().headerHidden = this.savedUIStates_.headerHidden; - }, - /** * Invoked when user clicks on the ok button. */
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 4e05050e..a7afdef2 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -124,6 +124,12 @@ lastBackMessageValue_: false, /** + * Flag for tests that saml page was loaded. + * @type {boolean} + */ + samlInterstitialPageReady: false, + + /** * Whether the dialog could be closed. * This is being checked in cancel() when user clicks on signin-back-button * (normal gaia flow) or the buttons in gaia-navigation (used in enterprise @@ -163,8 +169,6 @@ !isWhitelistError && !this.authCompleted_ && this.screenMode_ != ScreenMode.SAML_INTERSTITIAL; - $('login-header-bar').updateUI_(); - let showGuestInOobe = !this.closable && this.isAtTheBeginning(); chrome.send('showGuestInOobe', [showGuestInOobe]); }, @@ -581,10 +585,6 @@ chrome.send('loginVisible', ['gaia-loading']); }); - // Button header is always visible when sign in is presented. - // Header is hidden once GAIA reports on successful sign in. - Oobe.getInstance().headerHidden = false; - // Re-enable navigation in case it was disabled before refresh. this.navigationDisabled_ = false; @@ -711,10 +711,6 @@ this.authCompleted_ = false; this.lastBackMessageValue_ = false; - $('login-header-bar').showCreateSupervisedButton = - data.supervisedUsersCanCreate; - $('login-header-bar').showGuestButton = data.guestSignin; - // Reset SAML this.classList.toggle('full-width', false); $('saml-notice-container').hidden = true; @@ -782,6 +778,7 @@ if (this.loading) this.loading = false; // This event is for the browser tests. + this.samlInterstitialPageReady = true; $('saml-interstitial').fire('samlInterstitialPageReady'); break; } @@ -990,7 +987,6 @@ */ onAuthConfirmPassword_: function(email, passwordCount) { this.loading = true; - Oobe.getInstance().headerHidden = false; if (this.samlPasswordConfirmAttempt_ == 0) chrome.send('scrapedPasswordCount', [passwordCount]); @@ -1112,8 +1108,6 @@ $('signin-back-button').hidden = true; $('signin-frame-dialog').setAttribute('hide-shadow', true); - // Now that we're in logged in state header should be hidden. - Oobe.getInstance().headerHidden = true; // Clear any error messages that were shown before login. Oobe.clearErrors(); @@ -1160,9 +1154,6 @@ this.gaiaAuthHost_.resetStates(); if (takeFocus) { if (!forceOnline && this.isOffline()) { - // Show 'Cancel' button to allow user to return to the main screen - // (e.g. this makes sense when connection is back). - Oobe.getInstance().headerHidden = false; Oobe.getInstance().setSigninUIState(SIGNIN_UI_STATE.GAIA_SIGNIN); // Do nothing, since offline version is reloaded after an error comes. } else { @@ -1192,7 +1183,6 @@ */ showErrorBubble: function(loginAttempts, error) { if (this.isOffline()) { - $('add-user-button').hidden = true; // Reload offline version of the sign-in extension, which will show // error itself. chrome.send('offlineLogin', [this.email]); @@ -1311,7 +1301,6 @@ adAuthUI.errorState = errorState; this.authCompleted_ = false; this.loading = false; - Oobe.getInstance().headerHidden = false; } }; });
diff --git a/chrome/browser/resources/chromeos/login/screen_marketing_opt_in.js b/chrome/browser/resources/chromeos/login/screen_marketing_opt_in.js index d336724..ec93d97 100644 --- a/chrome/browser/resources/chromeos/login/screen_marketing_opt_in.js +++ b/chrome/browser/resources/chromeos/login/screen_marketing_opt_in.js
@@ -14,13 +14,5 @@ get defaultControl() { return $('marketing-opt-in-impl'); }, - - /** - * Event handler that is invoked just before the screen is shown. - * @param {object} data Screen init payload. - */ - onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; - } }; });
diff --git a/chrome/browser/resources/chromeos/login/screen_password_changed.js b/chrome/browser/resources/chromeos/login/screen_password_changed.js index 087a0822..0e70231 100644 --- a/chrome/browser/resources/chromeos/login/screen_password_changed.js +++ b/chrome/browser/resources/chromeos/login/screen_password_changed.js
@@ -19,12 +19,10 @@ 'cancel', this.cancel.bind(this)); this.gaiaPasswordChanged_.addEventListener('passwordEnter', function(e) { - $('login-header-bar').disabled = true; chrome.send('migrateUserData', [e.detail.password]); }); this.gaiaPasswordChanged_.addEventListener('proceedAnyway', function() { - $('login-header-bar').disabled = true; chrome.send('resyncUserData'); }); }, @@ -44,13 +42,6 @@ }, /** - * Event handler that is invoked just before the screen is hidden. - */ - onBeforeHide: function() { - $('login-header-bar').disabled = false; - }, - - /** * Show password changed screen. * @param {boolean} showError Whether to show the incorrect password error. */ @@ -62,10 +53,7 @@ this.gaiaPasswordChanged_.email = email; // We'll get here after the successful online authentication. - // It assumes session is about to start so hides login screen controls. - Oobe.getInstance().headerHidden = false; Oobe.showScreen({id: SCREEN_PASSWORD_CHANGED}); - $('login-header-bar').disabled = false; Oobe.getInstance().setSigninUIState(SIGNIN_UI_STATE.PASSWORD_CHANGED); } };
diff --git a/chrome/browser/resources/chromeos/login/screen_sync_consent.js b/chrome/browser/resources/chromeos/login/screen_sync_consent.js index 6526b748..88ffa78 100644 --- a/chrome/browser/resources/chromeos/login/screen_sync_consent.js +++ b/chrome/browser/resources/chromeos/login/screen_sync_consent.js
@@ -18,20 +18,10 @@ }, /** - * Event handler that is invoked just before the screen is shown. - * @param {object} data Screen init payload. - */ - onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; - $('login-header-bar').signinUIState = SIGNIN_UI_STATE.SYNC_CONSENT; - }, - - /** * Event handler that is invoked just before the screen is hidden. */ onBeforeHide: function() { this.setThrobberVisible(false /*visible*/); - $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN; }, /**
diff --git a/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js index 62ffc3b..2112a3bb 100644 --- a/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js +++ b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js
@@ -36,7 +36,6 @@ show: function() { this.setLoading_(false); - Oobe.getInstance().headerHidden = true; Oobe.showScreen({id: SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR}); },
diff --git a/chrome/browser/resources/chromeos/login/screen_update_required.js b/chrome/browser/resources/chromeos/login/screen_update_required.js index e454e32..0495969 100644 --- a/chrome/browser/resources/chromeos/login/screen_update_required.js +++ b/chrome/browser/resources/chromeos/login/screen_update_required.js
@@ -7,10 +7,5 @@ */ login.createScreen('UpdateRequiredScreen', 'update-required', function() { - return { - /** @Override */ - onBeforeShow: function(data) { - Oobe.getInstance().headerHidden = true; - } - }; + return {}; });
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css index e7af165..170f706 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css +++ b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
@@ -69,6 +69,7 @@ display: -webkit-box; height: 31px; margin-top: 8px; + overflow: hidden; pointer-events: auto; transition: border-top 130ms ease; user-select: none; @@ -93,6 +94,20 @@ font-weight: 500; line-height: 34px; padding: 0 30px; + position: relative; + transition: all 500ms ease; + width: 100%; +} + +.ink { + background: rgb(232, 240, 254); + border-radius: 100%; + position: absolute; + transform: scale(0); +} + +.ripple-category-list-item-animation { + animation: ripple-category-list-item 500ms linear; } #categories-list > li[selected] > div { @@ -868,3 +883,9 @@ transform: scale(1); } } + +@keyframes ripple-category-list-item { + 100% { opacity: 0; + transform: scale(2.5); + } +}
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_categories_list.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_categories_list.js index 4fd5313..0e0a4c8 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_categories_list.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_categories_list.js
@@ -70,9 +70,25 @@ var div = self.ownerDocument.createElement('div'); div.textContent = entry; li.appendChild(div); - li.addEventListener('mousedown', e => { - e.preventDefault(); - }); + div.addEventListener('mousedown', e => { + var targetEl = e.target; + var inkEl = targetEl.querySelector('.ink'); + if (inkEl) { + inkEl.classList.remove('ripple-category-list-item-animation'); + } else { + inkEl = document.createElement('span'); + inkEl.classList.add('ink'); + inkEl.style.width = inkEl.style.height = + Math.max(targetEl.offsetWidth, targetEl.offsetHeight) + 'px'; + targetEl.appendChild(inkEl); + } + inkEl.style.left = (e.offsetX - 0.5 * inkEl.offsetWidth) + 'px'; + inkEl.style.top = (e.offsetY - 0.5 * inkEl.offsetHeight) + 'px'; + inkEl.classList.add('ripple-category-list-item-animation'); + }); + li.addEventListener('mousedown', e => { + e.preventDefault(); + }); return li; }; },
diff --git a/chrome/browser/resources/feed_internals/feed_internals.css b/chrome/browser/resources/feed_internals/feed_internals.css index e65f136..c69244c 100644 --- a/chrome/browser/resources/feed_internals/feed_internals.css +++ b/chrome/browser/resources/feed_internals/feed_internals.css
@@ -10,6 +10,7 @@ } table { + table-layout: fixed; width: 100%; } @@ -19,9 +20,14 @@ table td { width: 50%; + word-wrap: break-word; } button { display: block; min-height: 30px; } + +#current-content table td:first-child { + width: 15%; +}
diff --git a/chrome/browser/resources/feed_internals/feed_internals.html b/chrome/browser/resources/feed_internals/feed_internals.html index 9a3c114..c96db826 100644 --- a/chrome/browser/resources/feed_internals/feed_internals.html +++ b/chrome/browser/resources/feed_internals/feed_internals.html
@@ -23,6 +23,7 @@ </head> <body> + <h2>Properties</h2> <table> <tr> @@ -30,6 +31,7 @@ <td id="is-feed-enabled"></td> </tr> </table> + <h2>User Classifier</h2> <table> <tr> @@ -52,6 +54,7 @@ <button id="clear-cached-data"> Clear Cache & Refresh Feed </button> + <h2>Last Fetch</h2> <table> <tr> @@ -67,5 +70,33 @@ <td id="refresh-suppress-time"></td> </tr> </table> + + <h2>Current Content</h2> + <div id="current-content"> + <template id="suggestion-template"> + <details> + <summary class="title"></summary> + <table> + <tr> + <td>Publisher Name</td> + <td class="publisher"></td> + </tr> + <tr> + <td>URL</td> + <td><a class="url"></a></td> + </tr> + <tr> + <td>Favicon URL</td> + <td><a class="favicon"></a></td> + </tr> + <tr> + <td>Image URL</td> + <td><a class="image"></a></td> + </tr> + </table> + </details> + </template> + </div> + </body> </html>
diff --git a/chrome/browser/resources/feed_internals/feed_internals.js b/chrome/browser/resources/feed_internals/feed_internals.js index 7e64c0b5..4d3df25 100644 --- a/chrome/browser/resources/feed_internals/feed_internals.js +++ b/chrome/browser/resources/feed_internals/feed_internals.js
@@ -51,6 +51,48 @@ } /** + * Get and display last known content. + */ +function updatePageWithCurrentContent() { + pageHandler.getCurrentContent().then(response => { + const before = $('current-content'); + const after = before.cloneNode(false); + + /** @type {!Array<feedInternals.mojom.Suggestion>} */ + const suggestions = response.suggestions; + + for (const suggestion of suggestions) { + // Create new content item from template. + const item = document.importNode($('suggestion-template').content, true); + + // Populate template with text metadata. + item.querySelector('.title').textContent = suggestion.title; + item.querySelector('.publisher').textContent = suggestion.publisherName; + + // Populate template with link metadata. + setLinkNode(item.querySelector('a.url'), suggestion.url); + setLinkNode(item.querySelector('a.image'), suggestion.imageUrl); + setLinkNode(item.querySelector('a.favicon'), suggestion.faviconUrl); + + after.appendChild(item); + } + + before.replaceWith(after); + }); +} + +/** + * Populate <a> node with hyperlinked URL. + * + * @param {Element} node + * @param {string} url + */ +function setLinkNode(node, url) { + node.textContent = url; + node.href = url; +} + +/** * Convert time to string for display. * * @param {feedInternals.mojom.Time|undefined} time @@ -78,6 +120,7 @@ // consider adding backend->frontend mojo communication to listen for // updates, rather than waiting an arbitrary period of time. setTimeout(updatePageWithLastFetchProperties, 1000); + setTimeout(updatePageWithCurrentContent, 1000); }); } @@ -88,6 +131,7 @@ updatePageWithProperties(); updatePageWithUserClass(); updatePageWithLastFetchProperties(); + updatePageWithCurrentContent(); setupEventListeners(); });
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js index e3282012..8d095c1 100644 --- a/chrome/browser/resources/feedback/js/feedback.js +++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -73,12 +73,13 @@ let isShowingSrtPrompt = false; /** - * Regular expression to check for all variants of bluetooth, blutooth, with or - * without space between the words and for BT when used as an individual word, - * or as two individual characters. Case insensitive matching. + * Regular expression to check for all variants of blu[e]toot[h] with or without + * space between the words; for BT when used as an individual word, or as two + * individual characters, and for BLE when used as an individual word. Case + * insensitive matching. * @type {RegExp} */ -const btRegEx = new RegExp('[b]lu[e]?[ ]?tooth|\b[b][ ]?[t]\b', 'i'); +const btRegEx = new RegExp('blu[e]?[ ]?toot[h]?|\\bb[ ]?t\\b|\\bble\\b', 'i'); /** * Regular expression to check for all strings indicating that a user can't
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js index 49935550..e864c86 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.js +++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -129,7 +129,6 @@ NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x', NOTIFICATION_MESSAGE: 'mv-msg', NTP_CONTENTS: 'ntp-contents', - OGB: 'one-google', PROMO: 'promo', RESTORE_ALL_LINK: 'mv-restore', SUGGESTIONS: 'suggestions', @@ -968,15 +967,32 @@ if (cmd === 'loaded') { tilesAreLoaded = true; if (configData.isGooglePage) { - // Show search suggestions, promo, and the OGB if they were previously - // hidden. + // Show search suggestions if they were previously hidden. if ($(IDS.SUGGESTIONS)) { $(IDS.SUGGESTIONS).style.visibility = 'visible'; } - if ($(IDS.PROMO)) { - $(IDS.PROMO).classList.remove(CLASSES.HIDE_PROMO); + if (!$('one-google-loader')) { + // Load the OneGoogleBar script. It'll create a global variable name + // "og" which is a dict corresponding to the native OneGoogleBarData + // type. We do this only after all the tiles have loaded, to avoid + // slowing down the main page load. + var ogScript = document.createElement('script'); + ogScript.id = 'one-google-loader'; + ogScript.src = 'chrome-search://local-ntp/one-google.js'; + document.body.appendChild(ogScript); + ogScript.onload = function() { + injectOneGoogleBar(og); + }; } - $(IDS.OGB).classList.remove('hidden'); + if (!$('promo-loader')) { + var promoScript = document.createElement('script'); + promoScript.id = 'promo-loader'; + promoScript.src = 'chrome-search://local-ntp/promo.js'; + document.body.appendChild(promoScript); + promoScript.onload = function() { + injectPromo(promo); + }; + } $(customBackgrounds.IDS.CUSTOM_LINKS_RESTORE_DEFAULT) .classList.toggle( customBackgrounds.CLASSES.OPTION_DISABLED, @@ -1013,15 +1029,11 @@ } } -/** - * Request data for search suggestions, promo, and the OGB. Insert it into - * the page once it's available. For search suggestions this should be almost - * immediately as cached data is always used. Promos and the OGB may need - * to wait for the asynchronous network request to complete. - */ -function requestAndInsertGoogleResources() { +function showSearchSuggestions() { + // Inject search suggestions as early as possible to avoid shifting of other + // elements. if (!$('search-suggestions-loader')) { - let ssScript = document.createElement('script'); + var ssScript = document.createElement('script'); ssScript.id = 'search-suggestions-loader'; ssScript.src = 'chrome-search://local-ntp/search-suggestions.js'; ssScript.async = false; @@ -1030,26 +1042,6 @@ injectSearchSuggestions(search_suggestions); }; } - if (!$('one-google-loader')) { - // Load the OneGoogleBar script. It'll create a global variable |og| which - // is a JSON object corresponding to the native OneGoogleBarData type. - let ogScript = document.createElement('script'); - ogScript.id = 'one-google-loader'; - ogScript.src = 'chrome-search://local-ntp/one-google.js'; - document.body.appendChild(ogScript); - ogScript.onload = function() { - injectOneGoogleBar(og); - }; - } - if (!$('promo-loader')) { - let promoScript = document.createElement('script'); - promoScript.id = 'promo-loader'; - promoScript.src = 'chrome-search://local-ntp/promo.js'; - document.body.appendChild(promoScript); - promoScript.onload = function() { - injectPromo(promo); - }; - } } @@ -1115,7 +1107,7 @@ var searchboxApiHandle = embeddedSearchApiHandle.searchBox; if (configData.isGooglePage) { - requestAndInsertGoogleResources(); + showSearchSuggestions(); enableMDIcons(); ntpApiHandle.onaddcustomlinkdone = onAddCustomLinkDone; @@ -1338,7 +1330,6 @@ let promoContainer = document.createElement('div'); promoContainer.id = IDS.PROMO; promoContainer.innerHTML += promo.promoHtml; - promoContainer.classList.add(CLASSES.HIDE_PROMO); $(IDS.NTP_CONTENTS).appendChild(promoContainer); if (promo.promoLogUrl) { @@ -1375,10 +1366,6 @@ * doesn't block the main page load. */ function injectOneGoogleBar(ogb) { - if (ogb.barHtml == '') { - return; - } - var inHeadStyle = document.createElement('style'); inHeadStyle.type = 'text/css'; inHeadStyle.appendChild(document.createTextNode(ogb.inHeadStyle)); @@ -1391,8 +1378,9 @@ renderOneGoogleBarTheme(); - var ogElem = $(IDS.OGB); + var ogElem = $('one-google'); ogElem.innerHTML = ogb.barHtml; + ogElem.classList.remove('hidden'); var afterBarScript = document.createElement('script'); afterBarScript.type = 'text/javascript';
diff --git a/chrome/browser/resources/md_user_manager/user_manager.html b/chrome/browser/resources/md_user_manager/user_manager.html index 43c8ecd4..375a5fe 100644 --- a/chrome/browser/resources/md_user_manager/user_manager.html +++ b/chrome/browser/resources/md_user_manager/user_manager.html
@@ -2,8 +2,7 @@ <html build="$i18n{buildType}" dir="$i18n{textdirection}" lang="$i18n{language}" - screen="$i18n{screenType}" - $i18n{dark}> + screen="$i18n{screenType}"> <head> <meta charset="utf-8"> <meta name="google" value="notranslate"> @@ -408,6 +407,5 @@ <include src="../../../../ui/login/account_picker/user_pod_template.html"> </user-manager-pages> <script src="user_manager.js"></script> - <link rel="import" href="chrome://resources/html/dark_mode.html"> </body> </html>
diff --git a/chrome/browser/resources/md_user_manager/user_manager.js b/chrome/browser/resources/md_user_manager/user_manager.js index 620f53d5..7a1d49a 100644 --- a/chrome/browser/resources/md_user_manager/user_manager.js +++ b/chrome/browser/resources/md_user_manager/user_manager.js
@@ -97,8 +97,7 @@ * displayed. */ UserManager.showUserManagerScreen = function(showGuest, showAddPerson) { - UserManager.getInstance().showScreen( - {id: 'account-picker', data: {disableAddUser: false}}); + UserManager.getInstance().showScreen({id: 'account-picker', data: {}}); // Hide control options if the user does not have the right permissions. const controlBar = document.querySelector('control-bar'); controlBar.showGuest = showGuest;
diff --git a/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chrome/browser/resources/plugin_metadata/plugins_linux.json index 8bcbb06..b427556 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_linux.json +++ b/chrome/browser/resources/plugin_metadata/plugins_linux.json
@@ -1,5 +1,5 @@ { - "x-version": 37, + "x-version": 38, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -10,9 +10,9 @@ ], "versions": [ { - "version": "32.0.0.114", + "version": "32.0.0.142", "status": "up_to_date", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-01.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-06.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chrome/browser/resources/plugin_metadata/plugins_mac.json index 3782472..06ce510 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_mac.json +++ b/chrome/browser/resources/plugin_metadata/plugins_mac.json
@@ -1,5 +1,5 @@ { - "x-version": 43, + "x-version": 44, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -7,9 +7,9 @@ ], "versions": [ { - "version": "32.0.0.114", + "version": "32.0.0.142", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-01.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-06.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json index 2c3ec10..2dedd10 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_win.json +++ b/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@ { - "x-version": 52, + "x-version": 53, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -7,9 +7,9 @@ ], "versions": [ { - "version": "32.0.0.114", + "version": "32.0.0.142", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-01.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-06.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/print_preview/print_preview_new.html b/chrome/browser/resources/print_preview/print_preview_new.html index e85a24c1..2917106 100644 --- a/chrome/browser/resources/print_preview/print_preview_new.html +++ b/chrome/browser/resources/print_preview/print_preview_new.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}" $i18n{dark}> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> <head> <meta charset="utf-8"> <style> @@ -22,6 +22,5 @@ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> <link rel="stylesheet" href="chrome://resources/css/md_colors.css"> <link rel="import" href="new/app.html"> - <link rel="import" href="chrome://resources/html/dark_mode.html"> </body> </html>
diff --git a/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chrome/browser/resources/safe_browsing/download_file_types.asciipb index 0cb38259..4d608e4 100644 --- a/chrome/browser/resources/safe_browsing/download_file_types.asciipb +++ b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,7 +8,7 @@ ## ## Top level settings ## -version_id: 31 +version_id: 32 sampled_ping_probability: 0.01 max_archived_binaries_to_report: 10 default_file_type { @@ -2826,6 +2826,16 @@ inspection_type: DMG } file_types { + extension: "mobileconfig" + uma_value: 356 + ping_setting: FULL_PING + platform_settings { + platform: PLATFORM_MAC + danger_level: ALLOW_ON_USER_GESTURE + auto_open_hint: DISALLOW_AUTO_OPEN + } +} +file_types { extension: "ndif" uma_value: 258 ping_setting: FULL_PING
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html index 3953ab06..28fa3ad2 100644 --- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html +++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -11,7 +11,17 @@ <dom-module id="settings-appearance-fonts-page"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + #minimumSize { + align-items: flex-end; + display: flex; + flex-direction: column; + } + + #minimumSizeSample { + text-align: end; + } + </style> <div class="settings-box first"> <div class="start">$i18n{fontSize}</div> <settings-slider id="sizeSlider" @@ -22,20 +32,20 @@ </div> <div class="settings-box"> <div class="start">$i18n{minimumFont}</div> - <div style=" - font-size:[[computeMinimumFontSize_( - prefs.webkit.webprefs.minimum_font_size.value)]]px; - font-family: - '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';"> - [[computeMinimumFontSize_( - prefs.webkit.webprefs.minimum_font_size.value)]]: - $i18n{quickBrownFox} + <div id="minimumSize"> + <settings-slider pref="{{prefs.webkit.webprefs.minimum_font_size}}" + ticks="[[minimumFontSizeRange_]]" label-min="$i18n{tiny}" + label-max="$i18n{huge}"></settings-slider> + <div id="minimumSizeSample" style=" + font-size:[[computeMinimumFontSize_( + prefs.webkit.webprefs.minimum_font_size.value)]]px; + font-family: + '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';"> + [[computeMinimumFontSize_( + prefs.webkit.webprefs.minimum_font_size.value)]]: + $i18n{quickBrownFox} + </div> </div> - <settings-slider id="minimumSizeSlider" - pref="{{prefs.webkit.webprefs.minimum_font_size}}" - ticks="[[minimumFontSizeRange_]]" - label-min="$i18n{tiny}" label-max="$i18n{huge}"> - </settings-slider> </div> <div class="settings-box"> <h2>$i18n{standardFont}</h2>
diff --git a/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html index d8015e55..bb92c4bd 100644 --- a/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html +++ b/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html
@@ -38,6 +38,12 @@ padding: 0 0 0 8px; } + :host-context([dark]) #expired { + background-color: unset; + font-weight: bold; + padding: 0; + } + #month { width: 70px; }
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html index 494ebd9e..43fec829 100644 --- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -101,7 +101,7 @@ $i18n{googleAssistantVoiceSettingsDescription} </div> </div> - <controlled-button id="button" class="secondary-button" + <controlled-button id="retrainVoiceModel" class="secondary-button" on-click="onRetrainVoiceModelTapped_" label="$i18n{googleAssistantVoiceSettingsRetrainButton}" pref="{{prefs.settings.voice_interaction.hotword.enabled}}">
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html index 0234eae..7696665 100644 --- a/chrome/browser/resources/settings/people_page/people_page.html +++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -56,16 +56,25 @@ } iron-icon[icon='cr:sync'] { - --iron-icon-fill-color: var(--google-green-700); + --iron-icon-fill-color: var(--google-green-refresh-700); + } + + :host-context([dark]) iron-icon[icon='cr:sync'] { + --iron-icon-fill-color: var(--google-green-refresh-300); } #sync-status[actionable] iron-icon[icon='settings:sync-problem'] { - --iron-icon-fill-color: var(--settings-error-color); + --iron-icon-fill-color: var(--settings-error-color); } #sync-status[actionable].auth-error iron-icon[icon='settings:sync-disabled'] { - --iron-icon-fill-color: var(--google-blue-500); + --iron-icon-fill-color: var(--google-blue-500); + } + + :host-context([dark]) #sync-status[actionable].auth-error + iron-icon[icon='settings:sync-disabled'] { + --iron-icon-fill-color: var(--google-blue-refresh-300); } #sync-status:not([actionable]) .subpage-arrow {
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html index ee4fa7a5..8c2ebc1 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -51,7 +51,6 @@ } #advancedButton { - background-color: unset; border: none; border-radius: initial; height: unset;
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index 52486aca..1d5cff0 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -33,10 +33,6 @@ flex-shrink: 0; /* Prevent distortion of icons in cramped UI. */ } - iron-icon[icon='cr:check'] { - --iron-icon-fill-color: var(--google-green-500); - } - iron-icon.policy { margin-inline-end: var(--cr-controlled-by-spacing); } @@ -64,11 +60,6 @@ margin-inline-start: var(--cr-icon-ripple-margin); } - /* For "Advanced" toggle button. */ - paper-button[toggles][active] { - background-color: var(--paper-grey-300); - } - /* Special case for buttons inside of toggle-buttons. */ .settings-box settings-toggle-button paper-button:last-of-type { margin-inline-end: 16px; @@ -115,10 +106,16 @@ } cr-radio-group:focus { + /* TODO(dbeam): why is this here? It looks weird and I'm not sure how to + * actually trigger it with mouse/keyboard/screenreader. */ background-color: var(--google-grey-300); outline: none; } + :host-context([dark]) cr-radio-group:focus { + background-color: var(--google-grey-800); + } + /* See also: .no-min-width below. */ .text-elide { @apply --cr-text-elide;
diff --git a/chrome/browser/resources/usb_internals/BUILD.gn b/chrome/browser/resources/usb_internals/BUILD.gn index 0a3f82b..2d9afb3b 100644 --- a/chrome/browser/resources/usb_internals/BUILD.gn +++ b/chrome/browser/resources/usb_internals/BUILD.gn
@@ -6,19 +6,20 @@ js_type_check("closure_compile") { deps = [ + ":device_page", ":usb_internals", ] } js_library("usb_internals") { - sources = [ - "usb_internals.js", - ] - deps = [ + ":device_page" "//chrome/browser/ui/webui/usb_internals:mojo_bindings_js_library_for_compile", "//ui/webui/resources/js:cr", "//ui/webui/resources/js:util", "//ui/webui/resources/js/cr/ui:tabs", ] } + +js_library("devices_page") { +}
diff --git a/chrome/browser/resources/usb_internals/devices_page.js b/chrome/browser/resources/usb_internals/devices_page.js new file mode 100644 index 0000000..134977c --- /dev/null +++ b/chrome/browser/resources/usb_internals/devices_page.js
@@ -0,0 +1,65 @@ +// Copyright 2019 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. + +/** + * Javascript for DevicesPage, served from + * chrome://usb-internals/. + */ + +cr.define('devices_page', function() { + /** + * Sets the device collection for the page's device table. + * @param {!Array<!device.mojom.UsbDeviceInfo>} devices + */ + function setDevices(devices) { + const tableBody = $('device-list'); + tableBody.innerHTML = ''; + + const rowTemplate = document.querySelector('#device-row'); + + for (const device of devices) { + const clone = document.importNode(rowTemplate.content, true); + + const td = clone.querySelectorAll('td'); + + td[0].textContent = device.busNumber; + td[1].textContent = device.portNumber; + td[2].textContent = toHex(device.vendorId); + td[3].textContent = toHex(device.productId); + if (device.manufacturerName) { + td[4].textContent = decodeString16(device.manufacturerName.data); + } + if (device.productName) { + td[5].textContent = decodeString16(device.productName.data); + } + if (device.serialNumber) { + td[6].textContent = decodeString16(device.serialNumber.data); + } + + tableBody.appendChild(clone); + } + } + + /** + * Parses utf16 coded string. + * @param {!mojoBase.mojom.String16} arr + * @return {string} + */ + function decodeString16(arr) { + return arr.map(ch => String.fromCodePoint(ch)).join(''); + } + + /** + * Parses the decimal number to hex format. + * @param {number} num + * @return {string} + */ + function toHex(num) { + return '0x' + num.toString(16).padStart(4, '0').slice(-4).toUpperCase(); + } + + return { + setDevices: setDevices, + }; +});
diff --git a/chrome/browser/resources/usb_internals/usb_internals.html b/chrome/browser/resources/usb_internals/usb_internals.html index cc025f8d..af7ff97c 100644 --- a/chrome/browser/resources/usb_internals/usb_internals.html +++ b/chrome/browser/resources/usb_internals/usb_internals.html
@@ -16,18 +16,26 @@ <script src="chrome://resources/js/cr/ui/tabs.js"></script> <script src="chrome://resources/js/mojo_bindings_lite.js"></script> <script src="chrome://resources/js/util.js"></script> - <script src="url/mojom/url.mojom-lite.js"></script> - <script src="device/usb/public/mojom/device_manager_test.mojom-lite.js"> - </script> - <script - src="chrome/browser/ui/webui/usb_internals/usb_internals.mojom-lite.js"> - </script> + <script src="chrome://resources/js/big_buffer.mojom-lite.js"></script> + <script src="chrome://resources/js/file.mojom-lite.js"></script> + <script src="chrome://resources/js/string16.mojom-lite.js"></script> + + <script src="url.mojom-lite.js"></script> + <script src="device.mojom-lite.js"></script> + <script src="device_manager_client.mojom-lite.js"></script> + <script src="device_enumeration_options.mojom-lite.js"></script> + <script src="device_manager.mojom-lite.js"></script> + <script src="device_manager_test.mojom-lite.js"></script> + <script src="usb_internals.mojom-lite.js"></script> + + <script src="devices_page.js"></script> </head> <body> <tabbox> <tabs> <tab>Test Devices</tab> + <tab>Devices</tab> </tabs> <tabpanels> <tabpanel> @@ -82,6 +90,40 @@ </form> </div> </tabpanel> + + <tabpanel> + <!-- Devices --> + <h2>Devices</h2> + <table class="styled-table"> + <thead> + <tr> + <th>Bus Number</th> + <th>Port Number</th> + <th>Vendor Id</th> + <th>Product Id</th> + <th>Manufacturer Name</th> + <th>Product Name</th> + <th>Serial Number</th> + <th> + </tr> + </thead> + <tbody id="device-list"></tbody> + + <template id="device-row"> + <tr> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td><button>Inspect</button></td> + </tr> + </template> + + </table> + </tabpanel> </tabpanels> </tabbox>
diff --git a/chrome/browser/resources/usb_internals/usb_internals.js b/chrome/browser/resources/usb_internals/usb_internals.js index 09fe786..accc7df 100644 --- a/chrome/browser/resources/usb_internals/usb_internals.js +++ b/chrome/browser/resources/usb_internals/usb_internals.js
@@ -8,23 +8,36 @@ cr.define('usb_internals', function() { class UsbInternals { constructor() { + const pageHandler = mojom.UsbInternalsPageHandler.getProxy(); + // Connection to the UsbInternalsPageHandler instance running in the // browser process. - this.usbManagerTest = null; + /** @private {device.mojom.UsbDeviceManagerProxy} */ + this.usbManager_ = new device.mojom.UsbDeviceManagerProxy; + pageHandler.bindUsbDeviceManagerInterface( + this.usbManager_.$.createRequest()); - const pageHandler = mojom.UsbInternalsPageHandler.getProxy(); - this.usbManagerTest = new device.mojom.UsbDeviceManagerTestProxy; - pageHandler.bindTestInterface(this.usbManagerTest.$.createRequest()); + /** @private {device.mojom.UsbDeviceManagerTestProxy} */ + this.usbManagerTest_ = new device.mojom.UsbDeviceManagerTestProxy; + pageHandler.bindTestInterface(this.usbManagerTest_.$.createRequest()); cr.ui.decorate('tabbox', cr.ui.TabBox); + + this.refreshDeviceList(); + $('add-test-device-form').addEventListener('submit', (event) => { this.addTestDevice(event); }); - this.refreshDeviceList(); + this.refreshTestDeviceList(); } async refreshDeviceList() { - const response = await this.usbManagerTest.getTestDevices(); + const response = await this.usbManager_.getDevices(); + devices_page.setDevices(response.results); + } + + async refreshTestDeviceList() { + const response = await this.usbManagerTest_.getTestDevices(); const tableBody = $('test-device-list'); tableBody.innerHTML = ''; @@ -41,8 +54,8 @@ const removeButton = clone.querySelector('button'); removeButton.addEventListener('click', async () => { - await this.usbManagerTest.removeDeviceForTesting(device.guid); - this.refreshDeviceList(); + await this.usbManagerTest_.removeDeviceForTesting(device.guid); + this.refreshTestDeviceList(); }); tableBody.appendChild(clone); @@ -52,11 +65,11 @@ async addTestDevice(event) { event.preventDefault(); - const response = await this.usbManagerTest.addDeviceForTesting( + const response = await this.usbManagerTest_.addDeviceForTesting( $('test-device-name').value, $('test-device-serial').value, $('test-device-landing-page').value); if (response.success) { - this.refreshDeviceList(); + this.refreshTestDeviceList(); } $('add-test-device-result').textContent = response.message; @@ -72,4 +85,4 @@ document.addEventListener('DOMContentLoaded', () => { new usb_internals.UsbInternals(); -}); \ No newline at end of file +});
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 797df9d5..5f4d5103 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -269,6 +269,16 @@ "telemetry/android/android_telemetry_service.h", ] deps += [ "//components/safe_browsing/android:safe_browsing_mobile" ] + } else if (safe_browsing_mode == 3) { + sources += [ + "../loader/safe_browsing_resource_throttle.cc", + "../loader/safe_browsing_resource_throttle.h", + "android/services_delegate_android.cc", + "android/services_delegate_android.h", + "telemetry/android/android_telemetry_service.cc", + "telemetry/android/android_telemetry_service.h", + ] + deps += [ "//components/safe_browsing/db:db" ] } } }
diff --git a/chrome/browser/safe_browsing/android/services_delegate_android.cc b/chrome/browser/safe_browsing/android/services_delegate_android.cc index cc65b2a..dc8dc71 100644 --- a/chrome/browser/safe_browsing/android/services_delegate_android.cc +++ b/chrome/browser/safe_browsing/android/services_delegate_android.cc
@@ -7,9 +7,11 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h" #include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" #include "components/safe_browsing/android/remote_database_manager.h" +#include "components/safe_browsing/db/v4_local_database_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" @@ -52,10 +54,24 @@ void ServicesDelegateAndroid::Initialize() { if (!database_manager_set_for_tests_) { +#if defined(SAFE_BROWSING_DB_REMOTE) database_manager_ = base::WrapRefCounted(new RemoteSafeBrowsingDatabaseManager()); +#else + database_manager_ = V4LocalDatabaseManager::Create( + SafeBrowsingService::GetBaseFilename(), + base::BindRepeating( + &ServicesDelegateAndroid::GetEstimatedExtendedReportingLevel, + base::Unretained(this))); +#endif } } + +ExtendedReportingLevel +ServicesDelegateAndroid::GetEstimatedExtendedReportingLevel() const { + return safe_browsing_service_->estimated_extended_reporting_by_prefs(); +} + void ServicesDelegateAndroid::SetDatabaseManagerForTest( SafeBrowsingDatabaseManager* database_manager) { database_manager_set_for_tests_ = true;
diff --git a/chrome/browser/safe_browsing/android/services_delegate_android.h b/chrome/browser/safe_browsing/android/services_delegate_android.h index f821aa1..b1d8ac6 100644 --- a/chrome/browser/safe_browsing/android/services_delegate_android.h +++ b/chrome/browser/safe_browsing/android/services_delegate_android.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "chrome/browser/safe_browsing/services_delegate.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" namespace safe_browsing { @@ -55,6 +56,14 @@ std::string GetSafetyNetId() const override; + // Reports the current extended reporting level. Note that this is an + // estimation and may not always be correct. It is possible that the + // estimation finds both Scout and legacy extended reporting to be enabled. + // This can happen, for instance, if one profile has Scout enabled and another + // has legacy extended reporting enabled. In such a case, this method reports + // LEGACY as the current level. + ExtendedReportingLevel GetEstimatedExtendedReportingLevel() const; + SafeBrowsingService* const safe_browsing_service_; // The telemetry service tied to the current profile.
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h index 682813b..067730b 100644 --- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
@@ -51,6 +51,8 @@ void OnDownloadUpdated(download::DownloadItem* download) override; private: + friend class AndroidTelemetryServiceTest; + // Whether the ping can be sent, based on empty web_contents, or incognito // mode, or extended reporting opt-in status, bool CanSendPing(download::DownloadItem* item);
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc new file mode 100644 index 0000000..50b85d5 --- /dev/null +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc
@@ -0,0 +1,176 @@ +// Copyright 2019 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/safe_browsing/telemetry/android/android_telemetry_service.h" + +#include <memory> + +#include "base/task/post_task.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "components/download/public/common/mock_download_item.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" +#include "components/safe_browsing/features.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_item_utils.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace safe_browsing { + +class AndroidTelemetryServiceTest : public testing::Test { + public: + AndroidTelemetryServiceTest() = default; + + protected: + Profile* profile() { return profile_.get(); } + + void SetUp() override { + browser_process_ = TestingBrowserProcess::GetGlobal(); + + system_request_context_getter_ = + base::MakeRefCounted<net::TestURLRequestContextGetter>( + base::CreateSingleThreadTaskRunnerWithTraits( + {content::BrowserThread::IO})); + browser_process_->SetSystemRequestContext( + system_request_context_getter_.get()); + sb_service_ = + safe_browsing::SafeBrowsingService::CreateSafeBrowsingService(); + browser_process_->SetSafeBrowsingService(sb_service_.get()); + sb_service_->Initialize(); + base::RunLoop().RunUntilIdle(); + + download_item_.reset(new ::testing::NiceMock<download::MockDownloadItem>()); + profile_.reset(new TestingProfile()); + + telemetry_service_ = + std::make_unique<AndroidTelemetryService>(sb_service_.get(), profile()); + } + + void TearDown() override {} + + bool CanSendPing(download::DownloadItem* item) { + return telemetry_service_->CanSendPing(item); + } + + void SetOffTheRecordProfile() { + telemetry_service_->profile_ = profile()->GetOffTheRecordProfile(); + } + + void ResetProfile() { telemetry_service_->profile_ = profile(); } + + protected: + content::TestBrowserThreadBundle test_browser_thread_bundle_; + scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_; + std::unique_ptr<download::MockDownloadItem> download_item_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<AndroidTelemetryService> telemetry_service_; + TestingBrowserProcess* browser_process_; + scoped_refptr<net::URLRequestContextGetter> system_request_context_getter_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(AndroidTelemetryServiceTest, CantSendPing_NonApk) { + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault(testing::Return("text/plain")); + EXPECT_FALSE(CanSendPing(download_item_.get())); +} + +TEST_F(AndroidTelemetryServiceTest, CantSendPing_SafeBrowsingDisabled) { + // Disable Safe Browsing. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false); + + // Enable Scout Reporting. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, + true); + // Enable feature. + scoped_feature_list_.InitAndEnableFeature(kTelemetryForApkDownloads); + // Simulate APK download. + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault( + testing::Return("application/vnd.android.package-archive")); + + EXPECT_FALSE(CanSendPing(download_item_.get())); +} + +TEST_F(AndroidTelemetryServiceTest, CantSendPing_IncognitoMode) { + // No event is triggered if in incognito mode.. + SetOffTheRecordProfile(); + + // Enable Safe Browsing. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); + // Enable Scout Reporting. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, + true); + // Enable feature. + scoped_feature_list_.InitAndEnableFeature(kTelemetryForApkDownloads); + // Simulate APK download. + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault( + testing::Return("application/vnd.android.package-archive")); + + EXPECT_FALSE(CanSendPing(download_item_.get())); + + ResetProfile(); +} + +TEST_F(AndroidTelemetryServiceTest, CantSendPing_SBERDisabled) { + // Disable Scout Reporting. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, + false); + + // Enable Safe Browsing. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); + // Enable feature. + scoped_feature_list_.InitAndEnableFeature(kTelemetryForApkDownloads); + // Simulate APK download. + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault( + testing::Return("application/vnd.android.package-archive")); + + EXPECT_FALSE(CanSendPing(download_item_.get())); +} + +TEST_F(AndroidTelemetryServiceTest, CantSendPing_FeatureDisabled) { + // Disable feature. + scoped_feature_list_.InitAndDisableFeature(kTelemetryForApkDownloads); + + // Enable Safe Browsing. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); + // Enable Scout Reporting. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, + true); + // Simulate APK download. + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault( + testing::Return("application/vnd.android.package-archive")); + + EXPECT_FALSE(CanSendPing(download_item_.get())); +} + +TEST_F(AndroidTelemetryServiceTest, CanSendPing_AllConditionsMet) { + // Enable Safe Browsing. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); + // Enable Scout Reporting. + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, + true); + // Enable feature. + scoped_feature_list_.InitAndEnableFeature(kTelemetryForApkDownloads); + // Simulate APK download. + ON_CALL(*download_item_, GetMimeType()) + .WillByDefault( + testing::Return("application/vnd.android.package-archive")); + + // The ping should be sent. + EXPECT_TRUE(CanSendPing(download_item_.get())); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index cc26a4a..d1fbd87 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -367,42 +367,28 @@ return images; } -scoped_refptr<base::RefCountedString> GetOGBString( - const base::Optional<OneGoogleBarData>& og) { - base::DictionaryValue dict; - if (og.has_value()) { - dict.SetString("barHtml", og->bar_html); - dict.SetString("inHeadScript", og->in_head_script); - dict.SetString("inHeadStyle", og->in_head_style); - dict.SetString("afterBarScript", og->after_bar_script); - dict.SetString("endOfBodyHtml", og->end_of_body_html); - dict.SetString("endOfBodyScript", og->end_of_body_script); - } else { - dict.SetString("barHtml", std::string()); - } - - std::string js; - base::JSONWriter::Write(dict, &js); - js = "var og = " + js + ";"; - return scoped_refptr<base::RefCountedString>( - base::RefCountedString::TakeString(&js)); +std::unique_ptr<base::DictionaryValue> ConvertOGBDataToDict( + const OneGoogleBarData& og) { + auto result = std::make_unique<base::DictionaryValue>(); + result->SetString("barHtml", og.bar_html); + result->SetString("inHeadScript", og.in_head_script); + result->SetString("inHeadStyle", og.in_head_style); + result->SetString("afterBarScript", og.after_bar_script); + result->SetString("endOfBodyHtml", og.end_of_body_html); + result->SetString("endOfBodyScript", og.end_of_body_script); + return result; } -scoped_refptr<base::RefCountedString> GetPromoString( +std::unique_ptr<base::DictionaryValue> ConvertPromoDataToDict( const base::Optional<PromoData>& promo) { - base::DictionaryValue dict; + auto result = std::make_unique<base::DictionaryValue>(); if (promo.has_value()) { - dict.SetString("promoHtml", promo->promo_html); - dict.SetString("promoLogUrl", promo->promo_log_url.spec()); + result->SetString("promoHtml", promo->promo_html); + result->SetString("promoLogUrl", promo->promo_log_url.spec()); } else { - dict.SetString("promoHtml", std::string()); + result->SetString("promoHtml", std::string()); } - - std::string js; - base::JSONWriter::Write(dict, &js); - js = "var promo = " + js + ";"; - return scoped_refptr<base::RefCountedString>( - base::RefCountedString::TakeString(&js)); + return result; } std::unique_ptr<base::DictionaryValue> ConvertSearchSuggestDataToDict( @@ -545,10 +531,6 @@ UpdateConfigData(); } - bool DefaultSearchProviderIsGoogle() { - return search::DefaultSearchProviderIsGoogle(service_); - } - ~SearchConfigurationProvider() override { if (service_) service_->RemoveObserver(this); @@ -830,32 +812,40 @@ if (stripped_path == kOneGoogleBarScriptFilename) { if (!one_google_bar_service_) { callback.Run(nullptr); - } else { - ServeOneGoogleBarWhenAvailable(callback); + return; } + + one_google_bar_requests_.emplace_back(base::TimeTicks::Now(), callback); + one_google_bar_service_->Refresh(); + return; } if (stripped_path == kPromoScriptFilename) { if (!promo_service_) { callback.Run(nullptr); - } else { - ServePromoWhenAvailable(callback); + return; } + + // TODO(crbug/909931): There's no need to fetch the promo on each load, + // we can sometimes use cached data. + promo_requests_.emplace_back(base::TimeTicks::Now(), callback); + promo_service_->Refresh(); + return; } - // Search suggestions always used a cached value, so there is no need to - // refresh the data until the old data is used. if (stripped_path == kSearchSuggestionsScriptFilename) { if (!search_suggest_service_) { callback.Run(nullptr); - } else { - ServeSearchSuggestionsIfAvailable(callback); - - pending_search_suggest_request_ = base::TimeTicks::Now(); - search_suggest_service_->Refresh(); + return; } + + MaybeServeSearchSuggestions(callback); + + search_suggest_requests_.emplace_back(base::TimeTicks::Now()); + search_suggest_service_->Refresh(); + return; } @@ -891,10 +881,6 @@ #endif // !defined(GOOGLE_CHROME_BUILD) if (stripped_path == kMainHtmlFilename) { - if (search_config_provider_->DefaultSearchProviderIsGoogle()) { - InitiatePromoAndOGBRequests(); - } - std::string html = ui::ResourceBundle::GetSharedInstance() .GetRawDataResource(IDR_LOCAL_NTP_HTML) .as_string(); @@ -1150,40 +1136,37 @@ void LocalNtpSource::OnSearchSuggestDataUpdated() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (pending_search_suggest_request_.has_value()) { - return; - } - SearchSuggestLoader::Status result = search_suggest_service_->search_suggest_status(); - base::TimeDelta delta = - base::TimeTicks::Now() - *pending_search_suggest_request_; - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.SearchSuggestions.RequestLatency", - delta); - SearchSuggestionsRequestStatus request_status = - SearchSuggestionsRequestStatus::UNKNOWN_ERROR; + base::TimeTicks now = base::TimeTicks::Now(); + for (const auto& request : search_suggest_requests_) { + base::TimeDelta delta = now - request.start_time; + UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.SearchSuggestions.RequestLatency", + delta); + SearchSuggestionsRequestStatus request_status = + SearchSuggestionsRequestStatus::UNKNOWN_ERROR; - if (result == SearchSuggestLoader::Status::SIGNED_OUT) { - request_status = SearchSuggestionsRequestStatus::SIGNED_OUT; - } else if (result == SearchSuggestLoader::Status::OPTED_OUT) { - request_status = SearchSuggestionsRequestStatus::OPTED_OUT; - } else if (result == SearchSuggestLoader::Status::IMPRESSION_CAP) { - request_status = SearchSuggestionsRequestStatus::IMPRESSION_CAP; - } else if (result == SearchSuggestLoader::Status::REQUESTS_FROZEN) { - request_status = SearchSuggestionsRequestStatus::FROZEN; - } else if (result == SearchSuggestLoader::Status::OK) { - request_status = SearchSuggestionsRequestStatus::SENT; - UMA_HISTOGRAM_MEDIUM_TIMES( - "NewTabPage.SearchSuggestions.RequestLatency.Success", delta); - } else if (result == SearchSuggestLoader::Status::FATAL_ERROR) { - request_status = SearchSuggestionsRequestStatus::FATAL_ERROR; - UMA_HISTOGRAM_MEDIUM_TIMES( - "NewTabPage.SearchSuggestions.RequestLatency.Failure", delta); + if (result == SearchSuggestLoader::Status::SIGNED_OUT) { + request_status = SearchSuggestionsRequestStatus::SIGNED_OUT; + } else if (result == SearchSuggestLoader::Status::OPTED_OUT) { + request_status = SearchSuggestionsRequestStatus::OPTED_OUT; + } else if (result == SearchSuggestLoader::Status::IMPRESSION_CAP) { + request_status = SearchSuggestionsRequestStatus::IMPRESSION_CAP; + } else if (result == SearchSuggestLoader::Status::REQUESTS_FROZEN) { + request_status = SearchSuggestionsRequestStatus::FROZEN; + } else if (result == SearchSuggestLoader::Status::OK) { + request_status = SearchSuggestionsRequestStatus::SENT; + UMA_HISTOGRAM_MEDIUM_TIMES( + "NewTabPage.SearchSuggestions.RequestLatency.Success", delta); + } else if (result == SearchSuggestLoader::Status::FATAL_ERROR) { + request_status = SearchSuggestionsRequestStatus::FATAL_ERROR; + UMA_HISTOGRAM_MEDIUM_TIMES( + "NewTabPage.SearchSuggestions.RequestLatency.Failure", delta); + } + UMA_HISTOGRAM_ENUMERATION("NewTabPage.SearchSuggestions.RequestStatus", + request_status); } - UMA_HISTOGRAM_ENUMERATION("NewTabPage.SearchSuggestions.RequestStatus", - request_status); - - pending_search_suggest_request_ = base::nullopt; + search_suggest_requests_.clear(); } void LocalNtpSource::OnSearchSuggestServiceShuttingDown() { @@ -1192,8 +1175,7 @@ search_suggest_service_observer_.RemoveAll(); search_suggest_service_ = nullptr; } - -void LocalNtpSource::ServeSearchSuggestionsIfAvailable( +void LocalNtpSource::MaybeServeSearchSuggestions( const content::URLDataSource::GotDataCallback& callback) { base::Optional<SearchSuggestData> data = search_suggest_service_->search_suggest_data(); @@ -1213,89 +1195,59 @@ const base::Optional<OneGoogleBarData>& data) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!pending_one_google_bar_request_.has_value()) { + if (one_google_bar_requests_.empty()) return; - } scoped_refptr<base::RefCountedString> result; if (data.has_value()) { - result = GetOGBString(data); + std::string js; + base::JSONWriter::Write(*ConvertOGBDataToDict(*data), &js); + js = "var og = " + js + ";"; + result = base::RefCountedString::TakeString(&js); } - base::TimeDelta delta = - base::TimeTicks::Now() - *pending_one_google_bar_request_; - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.OneGoogleBar.RequestLatency", delta); - if (result) { - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.OneGoogleBar.RequestLatency.Success", - delta); - } else { - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.OneGoogleBar.RequestLatency.Failure", - delta); + base::TimeTicks now = base::TimeTicks::Now(); + for (const auto& request : one_google_bar_requests_) { + request.callback.Run(result); + base::TimeDelta delta = now - request.start_time; + UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.OneGoogleBar.RequestLatency", delta); + if (result) { + UMA_HISTOGRAM_MEDIUM_TIMES( + "NewTabPage.OneGoogleBar.RequestLatency.Success", delta); + } else { + UMA_HISTOGRAM_MEDIUM_TIMES( + "NewTabPage.OneGoogleBar.RequestLatency.Failure", delta); + } } - for (const auto& callback : one_google_bar_callbacks_) { - callback.Run(result); - } - pending_one_google_bar_request_ = base::nullopt; - one_google_bar_callbacks_.clear(); -} - -void LocalNtpSource::ServeOneGoogleBarWhenAvailable( - const content::URLDataSource::GotDataCallback& callback) { - base::Optional<OneGoogleBarData> data = - one_google_bar_service_->one_google_bar_data(); - - if (!pending_one_google_bar_request_.has_value()) { - callback.Run(GetOGBString(data)); - } else { - one_google_bar_callbacks_.emplace_back(callback); - } + one_google_bar_requests_.clear(); } void LocalNtpSource::ServePromo(const base::Optional<PromoData>& data) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!pending_promo_request_.has_value()) { + if (promo_requests_.empty()) return; - } - scoped_refptr<base::RefCountedString> result = GetPromoString(data); + scoped_refptr<base::RefCountedString> result; + std::string js; + base::JSONWriter::Write(*ConvertPromoDataToDict(data), &js); + js = "var promo = " + js + ";"; + result = base::RefCountedString::TakeString(&js); - base::TimeDelta delta = base::TimeTicks::Now() - *pending_promo_request_; - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency", delta); - if (result) { - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency.Success", - delta); - } else { - UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency.Failure", - delta); + base::TimeTicks now = base::TimeTicks::Now(); + for (const auto& request : promo_requests_) { + request.callback.Run(result); + base::TimeDelta delta = now - request.start_time; + UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency", delta); + if (result) { + UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency.Success", + delta); + } else { + UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.Promos.RequestLatency.Failure", + delta); + } } - for (const auto& callback : promo_callbacks_) { - callback.Run(result); - } - pending_promo_request_ = base::nullopt; - promo_callbacks_.clear(); -} - -void LocalNtpSource::ServePromoWhenAvailable( - const content::URLDataSource::GotDataCallback& callback) { - base::Optional<PromoData> data = promo_service_->promo_data(); - - if (!pending_promo_request_.has_value()) { - callback.Run(GetPromoString(data)); - } else { - promo_callbacks_.emplace_back(callback); - } -} - -void LocalNtpSource::InitiatePromoAndOGBRequests() { - if (one_google_bar_service_) { - pending_one_google_bar_request_ = base::TimeTicks::Now(); - one_google_bar_service_->Refresh(); - } - if (promo_service_) { - pending_promo_request_ = base::TimeTicks::Now(); - promo_service_->Refresh(); - } + promo_requests_.clear(); } LocalNtpSource::NtpBackgroundRequest::NtpBackgroundRequest( @@ -1307,3 +1259,31 @@ const NtpBackgroundRequest&) = default; LocalNtpSource::NtpBackgroundRequest::~NtpBackgroundRequest() = default; + +LocalNtpSource::OneGoogleBarRequest::OneGoogleBarRequest( + base::TimeTicks start_time, + const content::URLDataSource::GotDataCallback& callback) + : start_time(start_time), callback(callback) {} + +LocalNtpSource::OneGoogleBarRequest::OneGoogleBarRequest( + const OneGoogleBarRequest&) = default; + +LocalNtpSource::OneGoogleBarRequest::~OneGoogleBarRequest() = default; + +LocalNtpSource::PromoRequest::PromoRequest( + base::TimeTicks start_time, + const content::URLDataSource::GotDataCallback& callback) + : start_time(start_time), callback(callback) {} + +LocalNtpSource::PromoRequest::PromoRequest(const PromoRequest&) = default; + +LocalNtpSource::PromoRequest::~PromoRequest() = default; + +LocalNtpSource::SearchSuggestRequest::SearchSuggestRequest( + base::TimeTicks start_time) + : start_time(start_time) {} + +LocalNtpSource::SearchSuggestRequest::SearchSuggestRequest( + const SearchSuggestRequest&) = default; + +LocalNtpSource::SearchSuggestRequest::~SearchSuggestRequest() = default;
diff --git a/chrome/browser/search/local_ntp_source.h b/chrome/browser/search/local_ntp_source.h index a94d670..7a4811f 100644 --- a/chrome/browser/search/local_ntp_source.h +++ b/chrome/browser/search/local_ntp_source.h
@@ -69,6 +69,35 @@ content::URLDataSource::GotDataCallback callback; }; + struct OneGoogleBarRequest { + OneGoogleBarRequest( + base::TimeTicks start_time, + const content::URLDataSource::GotDataCallback& callback); + OneGoogleBarRequest(const OneGoogleBarRequest&); + ~OneGoogleBarRequest(); + + base::TimeTicks start_time; + content::URLDataSource::GotDataCallback callback; + }; + + struct PromoRequest { + PromoRequest(base::TimeTicks start_time, + const content::URLDataSource::GotDataCallback& callback); + PromoRequest(const PromoRequest&); + ~PromoRequest(); + + base::TimeTicks start_time; + content::URLDataSource::GotDataCallback callback; + }; + + struct SearchSuggestRequest { + explicit SearchSuggestRequest(base::TimeTicks start_time); + explicit SearchSuggestRequest(const SearchSuggestRequest&); + ~SearchSuggestRequest(); + + base::TimeTicks start_time; + }; + // Overridden from content::URLDataSource: std::string GetSource() const override; void StartDataRequest( @@ -102,32 +131,13 @@ void OnSearchSuggestDataUpdated() override; void OnSearchSuggestServiceShuttingDown() override; - // Called when the OGB data is available and serves |data| to any pending - // request from the NTP. void ServeOneGoogleBar(const base::Optional<OneGoogleBarData>& data); - // Called when the page requests OGB data. If the data is available it - // is returned immediately, otherwise it is returned when it becomes available - // in ServeOneGoogleBar. - void ServeOneGoogleBarWhenAvailable( - const content::URLDataSource::GotDataCallback& callback); - // Called when the promo data is available and serves |data| to any pending - // requests from the NTP. void ServePromo(const base::Optional<PromoData>& data); - // Called when the page requests promo data. If the data is available it - // is returned immediately, otherwise it is returned when it becomes - // available in ServePromo. - void ServePromoWhenAvailable( - const content::URLDataSource::GotDataCallback& callback); - // If suggestion data is available return it immediately, otherwise no search - // suggestions will be shown on this NTP load. - void ServeSearchSuggestionsIfAvailable( + void MaybeServeSearchSuggestions( const content::URLDataSource::GotDataCallback& callback); - // Start requests for the promo and OGB. - void InitiatePromoAndOGBRequests(); - Profile* const profile_; std::vector<NtpBackgroundRequest> ntp_background_collections_requests_; @@ -138,23 +148,20 @@ ScopedObserver<NtpBackgroundService, NtpBackgroundServiceObserver> ntp_background_service_observer_; - base::Optional<base::TimeTicks> pending_one_google_bar_request_; - std::vector<content::URLDataSource::GotDataCallback> - one_google_bar_callbacks_; + std::vector<OneGoogleBarRequest> one_google_bar_requests_; OneGoogleBarService* one_google_bar_service_; ScopedObserver<OneGoogleBarService, OneGoogleBarServiceObserver> one_google_bar_service_observer_; - base::Optional<base::TimeTicks> pending_promo_request_; - std::vector<content::URLDataSource::GotDataCallback> promo_callbacks_; + std::vector<PromoRequest> promo_requests_; PromoService* promo_service_; ScopedObserver<PromoService, PromoServiceObserver> promo_service_observer_; - base::Optional<base::TimeTicks> pending_search_suggest_request_; + std::vector<SearchSuggestRequest> search_suggest_requests_; SearchSuggestService* search_suggest_service_;
diff --git a/chrome/browser/signin/identity_test_environment_profile_adaptor.cc b/chrome/browser/signin/identity_test_environment_profile_adaptor.cc index 5de5dcd5..a390178a 100644 --- a/chrome/browser/signin/identity_test_environment_profile_adaptor.cc +++ b/chrome/browser/signin/identity_test_environment_profile_adaptor.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "components/signin/core/browser/test_image_decoder.h" namespace {
diff --git a/chrome/browser/site_isolation_policy.cc b/chrome/browser/site_isolation_policy.cc new file mode 100644 index 0000000..c173be4 --- /dev/null +++ b/chrome/browser/site_isolation_policy.cc
@@ -0,0 +1,22 @@ +// Copyright 2019 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/site_isolation_policy.h" + +#include "chrome/common/chrome_features.h" +#include "content/public/browser/site_isolation_policy.h" + +// static +bool SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() { + // Ignore attempts to add new isolated origins when site isolation is turned + // off, for example via a command-line switch, or via a content/ embedder + // that turns site isolation off for low-memory devices. + if (!content::SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled()) + return false; + + // The feature needs to be checked last, because checking the feature + // activates the field trial and assigns the client either to a control or an + // experiment group - such assignment should be final. + return base::FeatureList::IsEnabled(features::kSiteIsolationForPasswordSites); +}
diff --git a/chrome/browser/site_isolation_policy.h b/chrome/browser/site_isolation_policy.h new file mode 100644 index 0000000..34f0979 --- /dev/null +++ b/chrome/browser/site_isolation_policy.h
@@ -0,0 +1,25 @@ +// Copyright 2019 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_SITE_ISOLATION_POLICY_H_ +#define CHROME_BROWSER_SITE_ISOLATION_POLICY_H_ + +#include "base/macros.h" + +// A centralized place for making policy decisions about site isolation modes +// at the chrome/ layer. This supplements content::SiteIsolationPolicy with +// features that are specific to chrome/. +// +// These methods can be called from any thread. +class SiteIsolationPolicy { + public: + // Returns true if the site isolation mode for isolating sites where users + // enter passwords is enabled. + static bool IsIsolationForPasswordSitesEnabled(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy); +}; + +#endif // CHROME_BROWSER_SITE_ISOLATION_POLICY_H_
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.cc b/chrome/browser/speech/extension_api/tts_extension_api.cc index d0a967b..b8fa9d2 100644 --- a/chrome/browser/speech/extension_api/tts_extension_api.cc +++ b/chrome/browser/speech/extension_api/tts_extension_api.cc
@@ -293,7 +293,7 @@ } ExtensionFunction::ResponseAction TtsStopSpeakingFunction::Run() { - content::TtsController::GetInstance()->Stop(); + content::TtsController::GetInstance()->Stop(source_url()); return RespondNow(NoArguments()); }
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc index 4c1b8bda..240afa5 100644 --- a/chrome/browser/ssl/security_state_tab_helper.cc +++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -42,7 +42,7 @@ #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" #endif // defined(OS_CHROMEOS) -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #endif @@ -210,7 +210,7 @@ case safe_browsing::SB_THREAT_TYPE_URL_UNWANTED: return security_state::MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE; case safe_browsing::SB_THREAT_TYPE_SIGN_IN_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) if (safe_browsing::ChromePasswordProtectionService:: ShouldShowPasswordReusePageInfoBubble( web_contents(), @@ -224,7 +224,7 @@ return security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING; #endif case safe_browsing::SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) if (safe_browsing::ChromePasswordProtectionService:: ShouldShowPasswordReusePageInfoBubble( web_contents(),
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc index cab4239..2a5e625 100644 --- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc +++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -1752,6 +1752,10 @@ helper->GetSecurityInfo(&security_info); EXPECT_EQ(security_state::DANGEROUS, security_info.security_level); EXPECT_EQ(blink::kWebSecurityStyleInsecure, observer.latest_security_style()); + const content::SecurityStyleExplanations& http_explanation = + observer.latest_explanations(); + EXPECT_EQ(l10n_util::GetStringUTF8(IDS_HTTP_NONSECURE_SUMMARY), + http_explanation.summary); } // Visit a valid HTTPS page, then a broken HTTPS page, and then go back, @@ -2027,6 +2031,10 @@ // Verify that the security state degrades as expected. helper->GetSecurityInfo(&security_info); EXPECT_EQ(security_state::DANGEROUS, security_info.security_level); + const content::SecurityStyleExplanations& http_explanation = + observer.latest_explanations(); + EXPECT_EQ(l10n_util::GetStringUTF8(IDS_HTTP_NONSECURE_SUMMARY), + http_explanation.summary); // Verify security state stays degraded after same-page navigation. ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc index 58827ca..52d82134 100644 --- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc +++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_switches.h" #include "chrome/test/base/ui_test_utils.h" #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h" #include "components/subresource_filter/core/common/test_ruleset_utils.h" @@ -387,6 +388,96 @@ 1 /* expected_count */); } +enum class NavigationInitiationType { + kWindowOpen, + kSetLocation, + kAnchorLinkActivate, +}; + +class AdClickNavigationBrowserTest + : public AdTaggingBrowserTest, + public ::testing::WithParamInterface< + std::tuple<NavigationInitiationType, bool /* gesture */>> { + void SetUpCommandLine(base::CommandLine* command_line) override { + // Popups without user gesture is blocked by default. Turn off the switch + // here to unblock that, so as to be able to test that the UseCounter not + // being recorded was due to the filtering in our recording function, rather + // than the default popup blocking. + command_line->AppendSwitch(::switches::kDisablePopupBlocking); + } +}; + +IN_PROC_BROWSER_TEST_P(AdClickNavigationBrowserTest, UseCounter) { + NavigationInitiationType type; + bool gesture; + std::tie(type, gesture) = GetParam(); + auto web_feature_waiter = + std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>( + GetWebContents()); + blink::mojom::WebFeature ad_click_navigation_feature = + blink::mojom::WebFeature::kAdClickNavigation; + web_feature_waiter->AddWebFeatureExpectation(ad_click_navigation_feature); + GURL url = + embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html"); + + ui_test_utils::NavigateToURL(browser(), url); + content::WebContents* main_tab = GetWebContents(); + RenderFrameHost* child = CreateSrcFrame( + main_tab, embedded_test_server()->GetURL( + "a.com", "/ad_tagging/frame_factory.html?1&ad=true")); + + std::string script; + switch (type) { + case NavigationInitiationType::kWindowOpen: + script = "window.open('frame_factory.html')"; + break; + case NavigationInitiationType::kSetLocation: + script = "location='frame_factory.html'"; + break; + case NavigationInitiationType::kAnchorLinkActivate: + script = + "var a = document.createElement('a');" + "a.setAttribute('href', 'frame_factory.html');" + "a.click();"; + break; + } + + if (gesture) { + EXPECT_TRUE(ExecJs(child, script)); + web_feature_waiter->Wait(); + } else { + switch (type) { + case NavigationInitiationType::kSetLocation: + case NavigationInitiationType::kAnchorLinkActivate: { + content::TestNavigationObserver navigation_observer(web_contents()); + EXPECT_TRUE(ExecuteScriptWithoutUserGesture(child, script)); + // To report metrics. + navigation_observer.Wait(); + break; + } + case NavigationInitiationType::kWindowOpen: { + EXPECT_TRUE(ExecuteScriptWithoutUserGesture(child, script)); + // To report metrics. + ASSERT_EQ(2, browser()->tab_strip_model()->count()); + browser()->tab_strip_model()->MoveSelectedTabsTo(0); + ui_test_utils::NavigateToURL(browser(), url); + break; + } + } + EXPECT_FALSE( + web_feature_waiter->DidObserveWebFeature(ad_click_navigation_feature)); + } +} + +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + AdClickNavigationBrowserTest, + ::testing::Combine( + ::testing::Values(NavigationInitiationType::kWindowOpen, + NavigationInitiationType::kSetLocation, + NavigationInitiationType::kAnchorLinkActivate), + ::testing::Bool())); + class AdTaggingEventFromSubframeBrowserTest : public AdTaggingBrowserTest, public ::testing::WithParamInterface<
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 475d418..d38c4555 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -125,6 +125,7 @@ #include "chrome/browser/chromeos/printing/synced_printers_manager.h" #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h" #include "chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h" +#include "chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h" #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h" #include "components/arc/arc_util.h" #endif // defined(OS_CHROMEOS) @@ -448,8 +449,16 @@ #if defined(OS_CHROMEOS) if (arc::IsArcAllowedForProfile(profile_) && !arc::IsArcAppSyncFlowDisabled()) { - controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>( - syncer::ARC_PACKAGE, dump_stack, sync_service, this, profile_)); + if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSArcPackage)) { + controllers.push_back(std::make_unique<ArcPackageSyncModelTypeController>( + GetModelTypeStoreService()->GetStoreFactory(), + base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType, + base::Unretained(this), syncer::ARC_PACKAGE), + dump_stack, sync_service, profile_)); + } else { + controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>( + syncer::ARC_PACKAGE, dump_stack, sync_service, this, profile_)); + } } #endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc b/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc index 5fb85626..fb2ee0a0 100644 --- a/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc
@@ -3,10 +3,12 @@ // found in the LICENSE file. #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/integration/feature_toggler.h" #include "chrome/browser/sync/test/integration/sync_arc_package_helper.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h" +#include "components/sync/driver/sync_driver_switches.h" namespace arc { @@ -19,9 +21,11 @@ } // namespace -class SingleClientArcPackageSyncTest : public SyncTest { +class SingleClientArcPackageSyncTest : public FeatureToggler, public SyncTest { public: - SingleClientArcPackageSyncTest() : SyncTest(SINGLE_CLIENT) {} + SingleClientArcPackageSyncTest() + : FeatureToggler(switches::kSyncPseudoUSSArcPackage), + SyncTest(SINGLE_CLIENT) {} ~SingleClientArcPackageSyncTest() override {} @@ -29,13 +33,13 @@ DISALLOW_COPY_AND_ASSIGN(SingleClientArcPackageSyncTest); }; -IN_PROC_BROWSER_TEST_F(SingleClientArcPackageSyncTest, ArcPackageEmpty) { +IN_PROC_BROWSER_TEST_P(SingleClientArcPackageSyncTest, ArcPackageEmpty) { ASSERT_TRUE(SetupSync()); ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); } -IN_PROC_BROWSER_TEST_F(SingleClientArcPackageSyncTest, +IN_PROC_BROWSER_TEST_P(SingleClientArcPackageSyncTest, ArcPackageInstallSomePackages) { ASSERT_TRUE(SetupSync()); @@ -49,4 +53,8 @@ ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); } +INSTANTIATE_TEST_SUITE_P(USS, + SingleClientArcPackageSyncTest, + ::testing::Values(false, true)); + } // namespace arc
diff --git a/chrome/browser/sync/test/integration/two_client_arc_package_sync_test.cc b/chrome/browser/sync/test/integration/two_client_arc_package_sync_test.cc index 528be3d..6eacfb7 100644 --- a/chrome/browser/sync/test/integration/two_client_arc_package_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_arc_package_sync_test.cc
@@ -3,9 +3,11 @@ // found in the LICENSE file. #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/integration/feature_toggler.h" #include "chrome/browser/sync/test/integration/sync_arc_package_helper.h" #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "chrome/browser/sync/test/integration/sync_test.h" +#include "components/sync/driver/sync_driver_switches.h" namespace arc { @@ -18,9 +20,13 @@ } // namespace -class TwoClientArcPackageSyncTest : public SyncTest { +class TwoClientArcPackageSyncTest : public FeatureToggler, public SyncTest { public: - TwoClientArcPackageSyncTest() : SyncTest(TWO_CLIENT) { DisableVerifier(); } + TwoClientArcPackageSyncTest() + : FeatureToggler(switches::kSyncPseudoUSSArcPackage), + SyncTest(TWO_CLIENT) { + DisableVerifier(); + } ~TwoClientArcPackageSyncTest() override {} @@ -28,13 +34,13 @@ DISALLOW_COPY_AND_ASSIGN(TwoClientArcPackageSyncTest); }; -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, StartWithNoPackages) { +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, StartWithNoPackages) { ASSERT_TRUE(SetupSync()); ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); } -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, StartWithSamePackages) { +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, StartWithSamePackages) { ASSERT_TRUE(SetupClients()); constexpr size_t kNumPackages = 5; @@ -50,7 +56,7 @@ // In this test, packages are installed before sync started. Client1 will have // package 0 to 4 installed while client2 has no package installed. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, OneClientHasPackagesAnotherHasNone) { ASSERT_TRUE(SetupClients()); @@ -68,7 +74,7 @@ // In this test, packages are installed before sync started. Client1 will have // package 0 to 9 installed and client2 will have package 0 to 4 installed. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, OneClientHasPackagesAnotherHasSubSet) { ASSERT_TRUE(SetupClients()); @@ -91,7 +97,7 @@ // In this test, packages are installed before sync started. Client1 will have // package 0 to 4 installed and client2 will have package 1 to 5 installed. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, StartWithDifferentPackages) { ASSERT_TRUE(SetupClients()); @@ -111,7 +117,7 @@ } // Tests package installaton after sync started. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, Install) { +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, Install) { ASSERT_TRUE(SetupSync()); ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); @@ -122,7 +128,7 @@ // In this test, packages are installed after sync started. Client1 installs // package 0 to 4 and client2 installs package 3 to 7. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, InstallDifferent) { +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, InstallDifferent) { ASSERT_TRUE(SetupSync()); ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); @@ -140,7 +146,7 @@ // Installs package from one client and uninstalls from another after sync // started. -IN_PROC_BROWSER_TEST_F(TwoClientArcPackageSyncTest, Uninstall) { +IN_PROC_BROWSER_TEST_P(TwoClientArcPackageSyncTest, Uninstall) { ASSERT_TRUE(SetupSync()); ASSERT_TRUE(AllProfilesHaveSameArcPackageDetails()); @@ -154,4 +160,8 @@ EXPECT_TRUE(AllProfilesHaveSameArcPackageDetails()); } +INSTANTIATE_TEST_SUITE_P(USS, + TwoClientArcPackageSyncTest, + ::testing::Values(false, true)); + } // namespace arc
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index b8f6ae2..12214ba 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -68,8 +68,6 @@ return gfx::kGoogleGrey600; case ThemeProperties::COLOR_CONTROL_BACKGROUND: return SK_ColorWHITE; - case ThemeProperties::COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT: - return SkColorSetA(SK_ColorWHITE, 0x8A); case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR: return SkColorSetRGB(0x28, 0x28, 0x28); default: @@ -251,8 +249,6 @@ return gfx::kGoogleBlue600; case COLOR_CONTROL_BACKGROUND: return SK_ColorWHITE; - case COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT: - return SkColorSetRGB(0x64, 0x64, 0x64); case COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR: // We shouldn't reach this case because the color is calculated from // others.
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h index 936ca703..35a8f3be 100644 --- a/chrome/browser/themes/theme_properties.h +++ b/chrome/browser/themes/theme_properties.h
@@ -111,9 +111,6 @@ // shelf. COLOR_TOOLBAR_VERTICAL_SEPARATOR, - // The color of the "instructions text" in an empty bookmarks bar. - COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT, - // Colors used for the detached (NTP) bookmark bar. COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND, COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR,
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 9ee09179..fb026f3 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -555,10 +555,6 @@ GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito), 0x4D); } - case ThemeProperties::COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT: - if (UsingDefaultTheme()) - break; - return GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito); case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR: if (UsingDefaultTheme()) break;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 9cddc24..17171ba 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1610,8 +1610,6 @@ "webui/chromeos/login/gaia_screen_handler.h", "webui/chromeos/login/hid_detection_screen_handler.cc", "webui/chromeos/login/hid_detection_screen_handler.h", - "webui/chromeos/login/kiosk_app_menu_handler.cc", - "webui/chromeos/login/kiosk_app_menu_handler.h", "webui/chromeos/login/kiosk_autolaunch_screen_handler.cc", "webui/chromeos/login/kiosk_autolaunch_screen_handler.h", "webui/chromeos/login/kiosk_enable_screen_handler.cc", @@ -3265,6 +3263,8 @@ "app_list/arc/arc_fast_app_reinstall_starter.h", "app_list/arc/arc_package_sync_data_type_controller.cc", "app_list/arc/arc_package_sync_data_type_controller.h", + "app_list/arc/arc_package_sync_model_type_controller.cc", + "app_list/arc/arc_package_sync_model_type_controller.h", "app_list/arc/arc_package_syncable_service.cc", "app_list/arc/arc_package_syncable_service.h", "app_list/arc/arc_package_syncable_service_factory.cc",
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc new file mode 100644 index 0000000..4685a3aa0 --- /dev/null +++ b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc
@@ -0,0 +1,53 @@ +// Copyright 2019 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/app_list/arc/arc_package_sync_model_type_controller.h" + +#include <utility> + +#include "chrome/browser/chromeos/arc/arc_util.h" +#include "chrome/browser/profiles/profile.h" +#include "components/sync/driver/sync_service.h" + +ArcPackageSyncModelTypeController::ArcPackageSyncModelTypeController( + syncer::OnceModelTypeStoreFactory store_factory, + SyncableServiceProvider syncable_service_provider, + const base::RepeatingClosure& dump_stack, + syncer::SyncService* sync_service, + Profile* profile) + : syncer::SyncableServiceBasedModelTypeController( + syncer::ARC_PACKAGE, + std::move(store_factory), + std::move(syncable_service_provider), + dump_stack), + sync_service_(sync_service), + profile_(profile) { + arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); + if (arc_session_manager) { + arc_session_manager->AddObserver(this); + } +} + +ArcPackageSyncModelTypeController::~ArcPackageSyncModelTypeController() { + arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); + if (arc_session_manager) { + arc_session_manager->RemoveObserver(this); + } +} + +bool ArcPackageSyncModelTypeController::ReadyForStart() const { + DCHECK(CalledOnValidThread()); + return arc::IsArcPlayStoreEnabledForProfile(profile_); +} + +void ArcPackageSyncModelTypeController::OnArcPlayStoreEnabledChanged( + bool enabled) { + DCHECK(CalledOnValidThread()); + sync_service_->ReadyForStartChanged(type()); +} + +void ArcPackageSyncModelTypeController::OnArcInitialStart() { + DCHECK(CalledOnValidThread()); + sync_service_->ReadyForStartChanged(type()); +}
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h new file mode 100644 index 0000000..1f47081 --- /dev/null +++ b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h
@@ -0,0 +1,46 @@ +// Copyright 2019 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_APP_LIST_ARC_ARC_PACKAGE_SYNC_MODEL_TYPE_CONTROLLER_H_ +#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PACKAGE_SYNC_MODEL_TYPE_CONTROLLER_H_ + +#include "base/macros.h" +#include "chrome/browser/chromeos/arc/arc_session_manager.h" +#include "components/sync/driver/syncable_service_based_model_type_controller.h" + +class Profile; + +namespace syncer { +class SyncService; +} // namespace syncer + +// A DataTypeController for arc package sync datatypes, which enables or +// disables these types based on whether ArcAppInstance is ready. +class ArcPackageSyncModelTypeController + : public syncer::SyncableServiceBasedModelTypeController, + public arc::ArcSessionManager::Observer { + public: + // |dump_stack| is called when an unrecoverable error occurs. + ArcPackageSyncModelTypeController( + syncer::OnceModelTypeStoreFactory store_factory, + SyncableServiceProvider syncable_service_provider, + const base::RepeatingClosure& dump_stack, + syncer::SyncService* sync_service, + Profile* profile); + ~ArcPackageSyncModelTypeController() override; + + // DataTypeController overrides. + bool ReadyForStart() const override; + + // ArcSessionManager::Observer: + void OnArcPlayStoreEnabledChanged(bool enabled) override; + void OnArcInitialStart() override; + + private: + syncer::SyncService* const sync_service_; + Profile* const profile_; + + DISALLOW_COPY_AND_ASSIGN(ArcPackageSyncModelTypeController); +}; +#endif // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PACKAGE_SYNC_MODEL_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc index c6e06634..064cfee 100644 --- a/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc +++ b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc
@@ -120,6 +120,17 @@ pending_install_items_.end(); } +void ArcPackageSyncableService::WaitUntilReadyToSync(base::OnceClosure done) { + if (prefs_->package_list_initial_refreshed()) { + std::move(done).Run(); + return; + } + + // Wait until the initial list is loaded, handled in + // OnPackageListInitialRefreshed(). + wait_until_ready_to_sync_cb_ = std::move(done); +} + syncer::SyncMergeResult ArcPackageSyncableService::MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, @@ -322,6 +333,11 @@ SendSyncChange(package_info, SyncChange::ACTION_UPDATE); } +void ArcPackageSyncableService::OnPackageListInitialRefreshed() { + if (wait_until_ready_to_sync_cb_) + std::move(wait_until_ready_to_sync_cb_).Run(); +} + void ArcPackageSyncableService::SendSyncChange( const mojom::ArcPackageInfo& package_info, const syncer::SyncChange::SyncChangeType& sync_change_type) {
diff --git a/chrome/browser/ui/app_list/arc/arc_package_syncable_service.h b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.h index 1821e6e7..71c91cf3 100644 --- a/chrome/browser/ui/app_list/arc/arc_package_syncable_service.h +++ b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.h
@@ -55,6 +55,7 @@ bool IsPackageSyncing(const std::string& package_name) const; // syncer::SyncableService: + void WaitUntilReadyToSync(base::OnceClosure done) override; syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, @@ -79,6 +80,7 @@ void OnPackageModified(const mojom::ArcPackageInfo& package_info) override; void OnPackageRemoved(const std::string& package_name, bool uninstalled) override; + void OnPackageListInitialRefreshed() override; // Sends adds/updates sync change to sync server. void SendSyncChange( @@ -105,6 +107,7 @@ bool ShouldSyncPackage(const std::string& package_name) const; Profile* const profile_; + base::OnceClosure wait_until_ready_to_sync_cb_; std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_; std::unique_ptr<syncer::SyncErrorFactory> sync_error_handler_;
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc index 663f06a..e8cadef 100644 --- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc +++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
@@ -52,11 +52,11 @@ : AppListModelBuilder(controller, CrostiniAppItem::kItemType) {} CrostiniAppModelBuilder::~CrostiniAppModelBuilder() { - if (crostini_folder_observer_) { + if (crostini_folder_observer_) model_updater()->RemoveObserver(crostini_folder_observer_.get()); - } - // We don't need to remove ourself from the registry's observer list as these - // are both KeyedServices (this class lives on AppListSyncableService). + + crostini::CrostiniRegistryServiceFactory::GetForProfile(profile()) + ->RemoveObserver(this); } void CrostiniAppModelBuilder::BuildModel() {
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc index 1b1aceb..8d31670e 100644 --- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc +++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/ui/app_list/app_list_test_util.h" #include "chrome/browser/ui/app_list/chrome_app_list_item.h" #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h" -#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_profile.h" @@ -111,17 +110,14 @@ return std::make_unique<FakeAppListModelUpdater>(profile); }, profile())); - controller_ = std::make_unique<test::TestAppListControllerDelegate>(); + // The AppListSyncableService creates the CrostiniAppModelBuilder. sync_service_ = std::make_unique<app_list::AppListSyncableService>( profile_.get(), extensions::ExtensionSystem::Get(profile_.get())); - builder_ = std::make_unique<CrostiniAppModelBuilder>(controller_.get()); RemoveNonCrostiniApps(sync_service_.get()); } void ResetBuilder() { - builder_.reset(); sync_service_.reset(); - controller_.reset(); model_updater_factory_scope_.reset(); } @@ -133,9 +129,7 @@ return l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_APP_NAME); } - std::unique_ptr<test::TestAppListControllerDelegate> controller_; std::unique_ptr<app_list::AppListSyncableService> sync_service_; - std::unique_ptr<CrostiniAppModelBuilder> builder_; std::unique_ptr<CrostiniTestHelper> test_helper_; private:
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc index 426df68..69414f4 100644 --- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc +++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
@@ -6,6 +6,7 @@ #include <string> #include <utility> +#include "ash/public/cpp/app_types.h" #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/shelf_spinner_controller.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_client.h" +#include "chrome/browser/ui/ash/session_controller_client.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" @@ -252,21 +254,21 @@ void CrostiniAppWindowShelfController::RegisterAppWindow( aura::Window* window, const std::string& shelf_app_id) { + window->SetProperty(aura::client::kAppType, + static_cast<int>(ash::AppType::CROSTINI_APP)); const ash::ShelfID shelf_id(shelf_app_id); views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); aura_window_to_app_window_[window] = std::make_unique<AppWindowBase>(shelf_id, widget); AppWindowBase* app_window = aura_window_to_app_window_[window].get(); - const AccountId& current_user = - user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(); - const AccountId& window_owner = - MultiUserWindowManagerClient::GetInstance()->GetWindowOwner(window); // Only add an app to the shelf if it's associated with the currently active // user (which should always be the primary user at this time). - if (current_user == window_owner) { - AddToShelf(window, app_window); - } + if (SessionControllerClient::IsMultiProfileAvailable() && + user_manager::UserManager::Get()->GetActiveUser()->GetAccountId() != + MultiUserWindowManagerClient::GetInstance()->GetWindowOwner(window)) + return; + AddToShelf(window, app_window); } void CrostiniAppWindowShelfController::OnWindowDestroying(
diff --git a/chrome/browser/ui/ash/test_login_screen.cc b/chrome/browser/ui/ash/test_login_screen.cc index 9d3064d..9208a6d6 100644 --- a/chrome/browser/ui/ash/test_login_screen.cc +++ b/chrome/browser/ui/ash/test_login_screen.cc
@@ -113,7 +113,8 @@ bool show_full_management_disclosure) {} void TestLoginScreen::SetKioskApps( - std::vector<::ash::mojom::KioskAppInfoPtr> kiosk_apps) {} + std::vector<::ash::mojom::KioskAppInfoPtr> kiosk_apps, + SetKioskAppsCallback callback) {} void TestLoginScreen::ShowKioskAppError(const std::string& message) {}
diff --git a/chrome/browser/ui/ash/test_login_screen.h b/chrome/browser/ui/ash/test_login_screen.h index 9682606..df917695 100644 --- a/chrome/browser/ui/ash/test_login_screen.h +++ b/chrome/browser/ui/ash/test_login_screen.h
@@ -74,8 +74,8 @@ std::vector<::ash::mojom::InputMethodItemPtr> keyboard_layouts) override; void SetPublicSessionShowFullManagementDisclosure( bool show_full_management_disclosure) override; - void SetKioskApps( - std::vector<::ash::mojom::KioskAppInfoPtr> kiosk_apps) override; + void SetKioskApps(std::vector<::ash::mojom::KioskAppInfoPtr> kiosk_apps, + SetKioskAppsCallback callback) override; void ShowKioskAppError(const std::string& message) override; void NotifyOobeDialogState(ash::mojom::OobeDialogState state) override; void SetAddUserButtonEnabled(bool enable) override;
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index e04a1889..97d8593 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -12,6 +12,7 @@ #include "base/command_line.h" #include "base/debug/debugging_buildflags.h" #include "base/debug/profiler.h" +#include "base/feature_list.h" #include "base/macros.h" #include "base/metrics/user_metrics.h" #include "base/stl_util.h" @@ -43,6 +44,7 @@ #include "chrome/browser/ui/singleton_tabs.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/inspect_ui.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/content_restriction.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" @@ -412,6 +414,7 @@ break; case IDC_RESTORE_TAB: RestoreTab(browser_); + browser_->window()->OnTabRestored(IDC_RESTORE_TAB); break; case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(browser_); @@ -694,10 +697,14 @@ case IDC_WINDOW_PIN_TAB: PinTab(browser_); break; - case IDC_SHOW_MANAGEMENT_PAGE: - ShowSingletonTab(browser_, GURL(kChromeUIManagementURL)); + case IDC_SHOW_MANAGEMENT_PAGE: { + bool link_to_management_page = base::FeatureList::IsEnabled( + features::kLinkManagedNoticeToChromeUIManagementURL); + ShowSingletonTab(browser_, + GURL(link_to_management_page ? kChromeUIManagementURL + : kManagedUiLearnMoreUrl)); break; - + } // Hosted App commands case IDC_COPY_URL: CopyURL(browser_);
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index c5e2aa6..fb5ead30 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -209,9 +209,10 @@ virtual void OnTabDetached(content::WebContents* contents, bool was_active) = 0; - // Called when the user restores a tab from the recently closed tabs menu. - // |command_id| is the menu command associated with the restored tab. - virtual void OnTabRestoredFromMenu(int command_id) = 0; + // Called when the user restores a tab. |command_id| may be IDC_RESTORE_TAB or + // the menu command, depending on whether the tab was restored via keyboard or + // main menu. + virtual void OnTabRestored(int command_id) = 0; // Called to force the zoom state to for the active tab to be recalculated. // |can_show_bubble| is true when a user presses the zoom up or down keyboard
diff --git a/chrome/browser/ui/cocoa/first_run_dialog_controller.mm b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm index 48318e0..ed27bed 100644 --- a/chrome/browser/ui/cocoa/first_run_dialog_controller.mm +++ b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/cocoa/first_run_dialog_controller.h" #include "base/mac/scoped_nsobject.h" +#include "base/mac/sdk_forward_declarations.h" #include "chrome/browser/ui/cocoa/key_equivalent_constants.h" #include "chrome/browser/ui/cocoa/l10n_util.h" #include "chrome/grit/chromium_strings.h" @@ -65,9 +66,24 @@ } - (void)loadView { + BOOL isDarkMode = NO; + if (@available(macOS 10.14, *)) { + NSAppearanceName appearance = + [[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[ + NSAppearanceNameAqua, NSAppearanceNameDarkAqua + ]]; + isDarkMode = [appearance isEqual:NSAppearanceNameDarkAqua]; + } + NSColor* topBoxColor = isDarkMode + ? [NSColor colorWithCalibratedRed:0x32 / 255.0 + green:0x36 / 255.0 + blue:0x39 / 255.0 + alpha:1.0] + : [NSColor whiteColor]; + NSBox* topBox = [[[NSBox alloc] initWithFrame:NSMakeRect(0, 137, 480, 52)] autorelease]; - [topBox setFillColor:[NSColor whiteColor]]; + [topBox setFillColor:topBoxColor]; [topBox setBoxType:NSBoxCustom]; [topBox setBorderType:NSNoBorder]; [topBox setContentViewMargins:NSZeroSize];
diff --git a/chrome/browser/ui/cocoa/profiles/profile_menu_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_menu_controller.mm index 5e903ca..b257392 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_menu_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_menu_controller.mm
@@ -155,12 +155,10 @@ // The image might be too large and need to be resized (i.e. if this is // a signed-in user using the GAIA profile photo). - if (itemIcon.Width() > profiles::kAvatarIconWidth || - itemIcon.Height() > profiles::kAvatarIconHeight) { + if (itemIcon.Width() > profiles::kAvatarIconSize || + itemIcon.Height() > profiles::kAvatarIconSize) { itemIcon = profiles::GetAvatarIconForWebUI(itemIcon, true); } - DCHECK(itemIcon.Width() <= profiles::kAvatarIconWidth); - DCHECK(itemIcon.Height() <= profiles::kAvatarIconHeight); [item setImage:itemIcon.ToNSImage()]; [item setState:itemData.active ? NSOnState : NSOffState]; }
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc index fcf7940..4fd5da36 100644 --- a/chrome/browser/ui/libgtkui/gtk_ui.cc +++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -851,8 +851,6 @@ colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON] = tab_text_color; colors_[ThemeProperties::COLOR_TAB_TEXT] = tab_text_color; colors_[ThemeProperties::COLOR_BOOKMARK_TEXT] = tab_text_color; - colors_[ThemeProperties::COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT] = - tab_text_color; colors_[ThemeProperties::COLOR_BACKGROUND_TAB] = SK_ColorTRANSPARENT; colors_[ThemeProperties::COLOR_BACKGROUND_TAB_INACTIVE] = SK_ColorTRANSPARENT;
diff --git a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc index 849d1c5..76a98bf 100644 --- a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc +++ b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.cc
@@ -76,7 +76,6 @@ bool AlternateNavInfoBarDelegate::LinkClicked( WindowOpenDisposition disposition) { - DCHECK(match_); history::HistoryService* const history_service = HistoryServiceFactory::GetForProfile(profile_, ServiceAccessType::IMPLICIT_ACCESS);
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc index 44cb3ac..f9af799 100644 --- a/chrome/browser/ui/page_info/page_info.cc +++ b/chrome/browser/ui/page_info/page_info.cc
@@ -89,7 +89,7 @@ #include "chrome/browser/ui/page_info/page_info_infobar_delegate.h" #endif -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #endif @@ -97,10 +97,10 @@ using base::UTF8ToUTF16; using base::UTF16ToUTF8; using content::BrowserThread; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) using PasswordReuseEvent = safe_browsing::LoginReputationClientRequest::PasswordReuseEvent; -#endif // SAFE_BROWSING_DB_LOCAL +#endif // FULL_SAFE_BROWSING namespace { @@ -345,7 +345,7 @@ did_revoke_user_ssl_decisions_(false), profile_(profile), security_level_(security_state::NONE), -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) password_protection_service_( safe_browsing::ChromePasswordProtectionService:: GetPasswordProtectionService(profile_)), @@ -555,7 +555,7 @@ void PageInfo::OnChangePasswordButtonPressed( content::WebContents* web_contents) { -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) DCHECK(password_protection_service_); DCHECK(site_identity_status_ == SITE_IDENTITY_STATUS_SIGN_IN_PASSWORD_REUSE || site_identity_status_ == @@ -572,7 +572,7 @@ void PageInfo::OnWhitelistPasswordReuseButtonPressed( content::WebContents* web_contents) { -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) DCHECK(password_protection_service_); DCHECK(site_identity_status_ == SITE_IDENTITY_STATUS_SIGN_IN_PASSWORD_REUSE || site_identity_status_ == @@ -963,7 +963,7 @@ info.show_ssl_decision_revoke_button = show_ssl_decision_revoke_button_; info.show_change_password_buttons = show_change_password_buttons_; ui_->SetIdentityInfo(info); -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) if (password_protection_service_ && show_change_password_buttons_) { if (site_identity_status_ == SITE_IDENTITY_STATUS_SIGN_IN_PASSWORD_REUSE) { safe_browsing::LogWarningAction( @@ -1027,7 +1027,7 @@ l10n_util::GetStringUTF16(IDS_PAGE_INFO_UNWANTED_SOFTWARE_DETAILS); break; case security_state::MALICIOUS_CONTENT_STATUS_SIGN_IN_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) *status = PageInfo::SITE_IDENTITY_STATUS_SIGN_IN_PASSWORD_REUSE; // |password_protection_service_| may be null in test. *details = password_protection_service_ @@ -1037,7 +1037,7 @@ #endif break; case security_state::MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) *status = PageInfo::SITE_IDENTITY_STATUS_ENTERPRISE_PASSWORD_REUSE; // |password_protection_service_| maybe null in test. *details = password_protection_service_
diff --git a/chrome/browser/ui/page_info/page_info.h b/chrome/browser/ui/page_info/page_info.h index 2007d3c3f..7126842d 100644 --- a/chrome/browser/ui/page_info/page_info.h +++ b/chrome/browser/ui/page_info/page_info.h
@@ -285,7 +285,7 @@ security_state::SecurityLevel security_level_; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) // Used to handle changing password, and whitelisting site. safe_browsing::ChromePasswordProtectionService* password_protection_service_; #endif
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc index ca2d82f..224a2542 100644 --- a/chrome/browser/ui/page_info/page_info_ui.cc +++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -38,7 +38,7 @@ #include "ui/gfx/paint_vector_icon.h" #endif -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "components/safe_browsing/password_protection/password_protection_service.h" #endif @@ -288,12 +288,12 @@ IDS_PAGE_INFO_UNWANTED_SOFTWARE_SUMMARY, IDS_PAGE_INFO_UNWANTED_SOFTWARE_DETAILS); case PageInfo::SITE_IDENTITY_STATUS_SIGN_IN_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) return CreateSecurityDescriptionForPasswordReuse( /*is_enterprise_password=*/false); #endif case PageInfo::SITE_IDENTITY_STATUS_ENTERPRISE_PASSWORD_REUSE: -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) return CreateSecurityDescriptionForPasswordReuse( /*is_enterprise_password=*/true); #endif
diff --git a/chrome/browser/ui/page_info/page_info_ui.h b/chrome/browser/ui/page_info/page_info_ui.h index 4c3b503d3..75d32d06 100644 --- a/chrome/browser/ui/page_info/page_info_ui.h +++ b/chrome/browser/ui/page_info/page_info_ui.h
@@ -232,7 +232,7 @@ std::unique_ptr<PageInfoUI::SecurityDescription> GetSecurityDescription( const IdentityInfo& identity_info) const; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) // Creates security description for password reuse case. virtual std::unique_ptr<PageInfoUI::SecurityDescription> CreateSecurityDescriptionForPasswordReuse(
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc index 9acd12e..25693a4 100644 --- a/chrome/browser/ui/search/local_ntp_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -90,7 +90,7 @@ LocalNTPTest() : LocalNTPTest(/*enabled_features=*/{features::kUseGoogleLocalNtp}, - /*disabled_features=*/{}) {} + /*disabled_features=*/{features::kRemoveNtpFakebox}) {} void SetUpOnMainThread() override { // Some tests depend on the prepopulated most visited tiles coming from
diff --git a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc index b4f8918..942a62ce 100644 --- a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc
@@ -254,7 +254,8 @@ private: void SetUp() override { feature_list_.InitWithFeatures( - {features::kUseGoogleLocalNtp, features::kDoodlesOnLocalNtp}, {}); + {features::kUseGoogleLocalNtp, features::kDoodlesOnLocalNtp}, + {features::kRemoveNtpFakebox}); InProcessBrowserTest::SetUp(); }
diff --git a/chrome/browser/ui/search/local_ntp_uitest.cc b/chrome/browser/ui/search/local_ntp_uitest.cc index 79031a1..75468df 100644 --- a/chrome/browser/ui/search/local_ntp_uitest.cc +++ b/chrome/browser/ui/search/local_ntp_uitest.cc
@@ -35,7 +35,9 @@ private: void SetUp() override { - feature_list_.InitAndEnableFeature(features::kUseGoogleLocalNtp); + feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kUseGoogleLocalNtp}, + /*disabled_features=*/{features::kRemoveNtpFakebox}); InProcessBrowserTest::SetUp(); }
diff --git a/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc b/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc index 1e8bc483..37315dd3 100644 --- a/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc
@@ -31,7 +31,8 @@ private: void SetUp() override { - feature_list_.InitWithFeatures({features::kUseGoogleLocalNtp}, {}); + feature_list_.InitWithFeatures({features::kUseGoogleLocalNtp}, + {features::kRemoveNtpFakebox}); InProcessBrowserTest::SetUp(); }
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc index 5570d720..33d66a8 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -321,7 +321,7 @@ } } - browser_->window()->OnTabRestoredFromMenu(command_id); + browser_->window()->OnTabRestored(command_id); UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.OpenRecentTab", menu_opened_timer_.Elapsed());
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index 4152fa8f..10c680a 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -361,8 +361,12 @@ gfx::Insets insets(draggable_region->getBounds().bottom(), 0, 0, 0); // Invert the draggable regions to determine the additional client areas. + // Inversion should be computed for the difference between the inset area + // and the draggable_region -- draggable_region->getBounds() could have + // smaller width than widget's width. SkRegion inverted_region; - inverted_region.setRect(draggable_region->getBounds()); + inverted_region.setRect(0, 0, widget()->GetWindowBoundsInScreen().width(), + draggable_region->getBounds().bottom()); inverted_region.op(*draggable_region, SkRegion::kDifference_Op); std::vector<gfx::Rect> additional_client_regions; for (SkRegion::Iterator i(inverted_region); !i.done(); i.next())
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc index 8733a18..ee6ef08 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h" #include "chrome/browser/ui/views/chrome_constrained_window_views_client.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/test/view_event_test_base.h" @@ -426,7 +427,13 @@ BookmarkBarViewDragTestBase() = default; ~BookmarkBarViewDragTestBase() override = default; - virtual void OnWidgetDragWillStart() = 0; + void OnWidgetDragWillStart() { + const gfx::Point target = GetDragTargetInScreen(); + GetDragTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove), + target.x(), target.y())); + } virtual void OnWidgetDragComplete() { // All drag tests drag node f1a, so at the end of the test, if the node was @@ -465,6 +472,16 @@ CreateEventTask(this, &BookmarkBarViewDragTestBase::StartDrag)); } + virtual void AfterDragStarted() = 0; + + virtual void OnDragEntered() { + // Drop the element. + ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone( + ui_controls::LEFT, ui_controls::UP, + CreateEventTask(this, + &BookmarkBarViewDragTestBase::OnWidgetDragComplete))); + } + // Called after the drag ends; returns the node the test thinks should be the // dropped node. This is used to verify that the dragged node was dropped in // the expected position. @@ -475,21 +492,22 @@ private: void StartDrag() { - const gfx::Point target = GetDragTargetInScreen(); + const views::View* drag_view = + bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(0); + const gfx::Point current_position = + ui_test_utils::GetCenterInScreenCoordinates(drag_view); #if defined(USE_AURA) // TODO: fix this. Aura requires an additional mouse event to trigger drag // and drop checking state. EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - target.x() + 10, target.y(), + current_position.x() + 10, current_position.y(), CreateEventTask(this, &BookmarkBarViewDragTestBase::StartDrag2))); #else EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - target.x() + 10, target.y(), - CreateEventTask(this, - &BookmarkBarViewDragTestBase::OnWidgetDragWillStart))); + current_position.x() + 10, current_position.y(), + CreateEventTask(this, &BookmarkBarViewDragTestBase::AfterDragStarted))); - // See comment above this method as to why we do this. - ScheduleMouseMoveInBackground(target.x(), target.y()); + OnWidgetDragWillStart(); #endif } @@ -497,8 +515,7 @@ const gfx::Point target = GetDragTargetInScreen(); EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( target.x(), target.y(), - CreateEventTask(this, - &BookmarkBarViewDragTestBase::OnWidgetDragWillStart))); + CreateEventTask(this, &BookmarkBarViewDragTestBase::AfterDragStarted))); } GURL f1a_url_; @@ -776,32 +793,19 @@ // Tests drag and drop within the same menu. class BookmarkBarViewTest5 : public BookmarkBarViewDragTestBase { - public: - // BookmarkBarViewDragTestBase: - void OnWidgetDragWillStart() override { - // Drop the item so that it's now the second item. - views::MenuItemView* target_menu = - bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1); - gfx::Point loc(1, target_menu->height() - 2); - views::View::ConvertPointToScreen(target_menu, &loc); - ASSERT_TRUE(ui_controls::SendMouseMove(loc.x(), loc.y())); - - ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::UP, - CreateEventTask(this, &BookmarkBarViewTest5::OnWidgetDragComplete))); - } - protected: // BookmarkBarViewDragTestBase: + void AfterDragStarted() override { OnDragEntered(); } + const BookmarkNode* GetDroppedNode() const override { return model_->bookmark_bar_node()->GetChild(0)->GetChild(1); } gfx::Point GetDragTargetInScreen() const override { - views::MenuItemView* target_menu = + const views::View* target_view = bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1); - gfx::Point target(1, target_menu->height() - 1); - views::View::ConvertPointToScreen(target_menu, &target); + gfx::Point target(target_view->width() / 2, target_view->height() - 1); + views::View::ConvertPointToScreen(target_view, &target); return target; } }; @@ -848,17 +852,6 @@ // Tests drag and drop to different menu. class BookmarkBarViewTest7 : public BookmarkBarViewDragTestBase { public: - // BookmarkBarViewDragTestBase: - void OnWidgetDragWillStart() override { OnDropMenuShown(); } - - void OnWidgetDragComplete() override { - // The button should be in normal state now. - EXPECT_EQ(views::Button::STATE_NORMAL, - bb_view_->other_bookmarks_button()->state()); - - BookmarkBarViewDragTestBase::OnWidgetDragComplete(); - } - void OnDropMenuShown() { views::MenuItemView* drop_menu = bb_view_->GetDropMenu(); ASSERT_NE(nullptr, drop_menu); @@ -869,16 +862,29 @@ EXPECT_EQ(views::Button::STATE_PRESSED, bb_view_->other_bookmarks_button()->state()); - views::MenuItemView* target_menu = drop_submenu->GetMenuItemAt(0); - gfx::Point loc(1, 1); - views::View::ConvertPointToScreen(target_menu, &loc); + const views::View* target_view = drop_submenu->GetMenuItemAt(0); + + // Drag to the top of the target view. + gfx::Point target(target_view->width() / 2, 0); + views::View::ConvertPointToScreen(target_view, &target); ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - loc.x(), loc.y(), + target.x(), target.y(), CreateEventTask(this, &BookmarkBarViewTest7::OnDragEntered))); } + // BookmarkBarViewDragTestBase: + void OnWidgetDragComplete() override { + // The button should be in normal state now. + EXPECT_EQ(views::Button::STATE_NORMAL, + bb_view_->other_bookmarks_button()->state()); + + BookmarkBarViewDragTestBase::OnWidgetDragComplete(); + } + protected: // BookmarkBarViewDragTestBase: + void AfterDragStarted() override { OnDropMenuShown(); } + const BookmarkNode* GetDroppedNode() const override { return model_->other_node()->GetChild(0); } @@ -887,13 +893,6 @@ return ui_test_utils::GetCenterInScreenCoordinates( bb_view_->other_bookmarks_button()); } - - private: - void OnDragEntered() { - ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::UP, - CreateEventTask(this, &BookmarkBarViewTest7::OnWidgetDragComplete))); - } }; #if !defined(OS_WIN) @@ -907,37 +906,35 @@ // original menu. class BookmarkBarViewTest8 : public BookmarkBarViewDragTestBase { public: - // BookmarkBarViewDragTestBase: - void OnWidgetDragWillStart() override { OnDropMenuShown(); } - void OnDropMenuShown() { views::MenuItemView* drop_menu = bb_view_->GetDropMenu(); ASSERT_NE(nullptr, drop_menu); - ASSERT_TRUE(drop_menu->GetSubmenu()->IsShowing()); - - // Now drag back over first menu. - views::LabelButton* button = GetBookmarkButton(0); - gfx::Point loc = ui_test_utils::GetCenterInScreenCoordinates(button); - ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - loc.x(), loc.y(), - CreateEventTask(this, &BookmarkBarViewTest8::OnDragEntered))); - } - - void OnDragEntered() { - // Drop on folder F11. - views::MenuItemView* drop_menu = bb_view_->GetDropMenu(); - ASSERT_NE(nullptr, drop_menu); views::SubmenuView* drop_submenu = drop_menu->GetSubmenu(); ASSERT_TRUE(drop_submenu->IsShowing()); - views::MenuItemView* target_menu = drop_submenu->GetMenuItemAt(1); - ui_test_utils::MoveMouseToCenterAndPress( - target_menu, ui_controls::LEFT, ui_controls::UP, - CreateEventTask(this, &BookmarkBarViewTest8::OnWidgetDragComplete)); + const views::View* target_view; + base::OnceClosure task; + const auto* controller = + static_cast<const BookmarkMenuController*>(drop_menu->GetDelegate()); + if (controller->node() == model_->other_node()) { + // Now drag back over first menu. + target_view = GetBookmarkButton(0); + task = CreateEventTask(this, &BookmarkBarViewTest8::OnDropMenuShown); + } else { + // Drag to folder F11. + target_view = drop_submenu->GetMenuItemAt(1); + task = CreateEventTask(this, &BookmarkBarViewTest8::OnDragEntered); + } + const gfx::Point target = + ui_test_utils::GetCenterInScreenCoordinates(target_view); + ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone(target.x(), target.y(), + std::move(task))); } protected: // BookmarkBarViewDragTestBase: + void AfterDragStarted() override { OnDropMenuShown(); } + const BookmarkNode* GetDroppedNode() const override { return model_->bookmark_bar_node()->GetChild(0)->GetChild(0)->GetChild(1); } @@ -1941,29 +1938,29 @@ class BookmarkBarViewTest22 : public BookmarkBarViewDragTestBase { public: // BookmarkBarViewDragTestBase: - void OnWidgetDragWillStart() override { - OnDragEntered(); - OnWidgetDestroyed(); - } - void OnWidgetDestroyed() { -#if defined(OS_CHROMEOS) - ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::UP, - CreateEventTask(this, &BookmarkBarViewTest22::Done))); -#else - // There are no widgets to send the mouse release to. Done(); -#endif } protected: - void OnDragEntered() { + // BookmarkBarViewDragTestBase: + void AfterDragStarted() override { OnDragEntered(); } + + void OnDragEntered() override { +#if defined(OS_CHROMEOS) + ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone( + ui_controls::LEFT, ui_controls::UP, + CreateEventTask(this, &BookmarkBarViewTest22::OnWidgetDestroyed))); +#endif + window_->Close(); - window_ = NULL; + window_ = nullptr; + +#if !defined(OS_CHROMEOS) + OnWidgetDestroyed(); +#endif } - // BookmarkBarViewDragTestBase: const BookmarkNode* GetDroppedNode() const override { // This test doesn't check what happens on drop. return nullptr;
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc index 2cd40fc..c2655e4 100644 --- a/chrome/browser/ui/views/chrome_typography_provider.cc +++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -35,11 +35,11 @@ #endif constexpr char kUnspecifiedTypeface[] = ""; -// If the default foreground color from the native theme isn't black, the rest -// of the Harmony spec isn't going to work. Also skip Harmony if a Windows -// High Contrast theme is enabled. One of the four standard High Contrast themes -// in Windows 10 still has black text, but (since the user wants high contrast) -// the grey text shades in Harmony should not be used. +// If the default foreground color from the native theme isn't black and dark +// mode is not on the rest of the Harmony spec isn't going to work. Also skip +// Harmony if a Windows High Contrast theme is enabled. One of the four standard +// High Contrast themes in Windows 10 still has black text, but (since the user +// wants high contrast) the grey text shades in Harmony should not be used. bool ShouldIgnoreHarmonySpec(const ui::NativeTheme& theme) { // Mac provides users limited ways to customize the UI, including dark and // high contrast modes; all these are addressed elsewhere, so there's no need @@ -50,6 +50,8 @@ #else if (theme.UsesHighContrastColors()) return true; + if (theme.SystemDarkModeEnabled()) + return false; // TODO(pbos): Revisit this check. Both GG900 and black are considered // "default black" as the common theme uses GG900 as primary color.
diff --git a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.cc b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.cc index f86ec57..47da09f 100644 --- a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.cc +++ b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h" #include <memory> +#include <utility> #include "base/metrics/user_metrics.h" #include "base/strings/string_number_conversions.h" @@ -15,6 +16,7 @@ #include "ui/base/theme_provider.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/text_utils.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/label.h" #include "ui/views/event_monitor.h" @@ -39,34 +41,31 @@ FeaturePromoBubbleView::FeaturePromoBubbleView( views::View* anchor_view, views::BubbleBorder::Arrow arrow, + ActivationAction activation_action, int string_specifier, - ActivationAction activation_action) - : FeaturePromoBubbleView(anchor_view, - gfx::Rect(), - arrow, - string_specifier, - activation_action) {} - -FeaturePromoBubbleView::FeaturePromoBubbleView(const gfx::Rect& anchor_rect, - views::BubbleBorder::Arrow arrow, - int string_specifier) - : FeaturePromoBubbleView(nullptr, - anchor_rect, - arrow, - string_specifier, - ActivationAction::ACTIVATE) {} - -FeaturePromoBubbleView::FeaturePromoBubbleView( - views::View* anchor_view, - const gfx::Rect& anchor_rect, - views::BubbleBorder::Arrow arrow, - int string_specifier, - ActivationAction activation_action) + base::Optional<int> screenreader_string_specifier, + base::Optional<ui::Accelerator> feature_accelerator) : BubbleDialogDelegateView(anchor_view, arrow), activation_action_(activation_action) { + DCHECK(anchor_view); UseCompactMargins(); - if (!anchor_view) - SetAnchorRect(anchor_rect); + + const base::string16 body_text = l10n_util::GetStringUTF16(string_specifier); + + // Feature promos are purely informational. We can skip reading the UI + // elements inside the bubble and just have the information announced when the + // bubble shows. To do so, we change the a11y tree to make this a leaf node + // and set the name to the message we want to announce. + GetViewAccessibility().OverrideIsLeaf(true); + if (!screenreader_string_specifier) { + accessible_name_ = body_text; + } else if (feature_accelerator) { + accessible_name_ = l10n_util::GetStringFUTF16( + *screenreader_string_specifier, feature_accelerator->GetShortcutText()); + } else { + accessible_name_ = + l10n_util::GetStringUTF16(*screenreader_string_specifier); + } // We get the theme provider from the anchor view since our widget hasn't been // created yet. @@ -86,7 +85,7 @@ views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); SetLayoutManager(std::move(box_layout)); - auto* label = new views::Label(l10n_util::GetStringUTF16(string_specifier)); + auto* label = new views::Label(body_text); label->SetBackgroundColor(background_color); label->SetEnabledColor(text_color); AddChildView(label); @@ -107,8 +106,7 @@ ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH)); widget->Show(); - if (activation_action == ActivationAction::ACTIVATE) - StartAutoCloseTimer(kDelayDefault); + StartAutoCloseTimer(kDelayDefault); } FeaturePromoBubbleView::~FeaturePromoBubbleView() = default; @@ -117,10 +115,13 @@ FeaturePromoBubbleView* FeaturePromoBubbleView::CreateOwned( views::View* anchor_view, views::BubbleBorder::Arrow arrow, + ActivationAction activation_action, int string_specifier, - ActivationAction activation_action) { - return new FeaturePromoBubbleView(anchor_view, arrow, string_specifier, - activation_action); + base::Optional<int> screenreader_string_specifier, + base::Optional<ui::Accelerator> feature_accelerator) { + return new FeaturePromoBubbleView( + anchor_view, arrow, activation_action, string_specifier, + screenreader_string_specifier, feature_accelerator); } void FeaturePromoBubbleView::CloseBubble() { @@ -156,6 +157,16 @@ return bounds; } +ax::mojom::Role FeaturePromoBubbleView::GetAccessibleWindowRole() const { + // Since we don't have any controls for the user to interact with (we're just + // an information bubble), override our role to kAlert. + return ax::mojom::Role::kAlert; +} + +base::string16 FeaturePromoBubbleView::GetAccessibleWindowTitle() const { + return accessible_name_; +} + void FeaturePromoBubbleView::StartAutoCloseTimer( base::TimeDelta auto_close_duration) { timer_.Start(FROM_HERE, auto_close_duration, this,
diff --git a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h index 15053e6b..6cfe580 100644 --- a/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h +++ b/chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_FEATURE_PROMOS_FEATURE_PROMO_BUBBLE_VIEW_H_ #include "base/macros.h" +#include "base/optional.h" #include "base/timer/timer.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" @@ -15,6 +16,7 @@ } namespace ui { +class Accelerator; class MouseEvent; } @@ -31,44 +33,36 @@ ~FeaturePromoBubbleView() override; // Creates a promo bubble. The returned pointer is only valid until the widget - // is closed. It must not be manually deleted by the caller. |anchor_view| is - // the View this bubble is anchored to. |arrow| specifies where on the border - // the bubble's arrow is located. |string_specifier| is a string ID that can - // be passed to |l10n_util::GetStringUTF16()|. |activation_action| specifies - // whether the bubble's widget will be activated. + // is closed. It must not be manually deleted by the caller. + // * |anchor_view| is the View this bubble is anchored to. + // * |arrow| specifies where on the border the bubble's arrow is located. + // * |string_specifier| is a string ID that can be passed to + // |l10n_util::GetStringUTF16()|. + // * |screenreader_string_specifier| is an optional alternate string to be + // exposed to screen readers. + // * |feature_accelerator| is an optional keyboard accelerator to be announced + // by screen readers. If |screenreader_string_specifier| is used and has a + // placeholder, |feature_accelerator|'s shortcut text will be filled in. + // * |activation_action| specifies whether the bubble's widget will be + // activated. static FeaturePromoBubbleView* CreateOwned( views::View* anchor_view, views::BubbleBorder::Arrow arrow, + ActivationAction activation_action, int string_specifier, - ActivationAction activation_action); + base::Optional<int> screenreader_string_specifier = base::nullopt, + base::Optional<ui::Accelerator> feature_accelerator = base::nullopt); // Closes the promo bubble. void CloseBubble(); - protected: - // The |anchor_view| is used to anchor the FeaturePromoBubbleView. The |arrow| - // sets where the arrow hangs off the bubble and the |string_specifier| is - // the text that is displayed on the bubble. The |activation_action| sets if - // the bubble is active or not. - FeaturePromoBubbleView(views::View* anchor_view, - views::BubbleBorder::Arrow arrow, - int string_specifier, - ActivationAction activation_action); - - // The |anchor_rect| is used to anchor bubble views that have custom - // positioning requirements. The |arrow| sets where the arrow hangs off the - // bubble and the |string_specifier| is the text that is displayed on the - // bubble. - FeaturePromoBubbleView(const gfx::Rect& anchor_rect, - views::BubbleBorder::Arrow arrow, - int string_specifier); - private: FeaturePromoBubbleView(views::View* anchor_view, - const gfx::Rect& anchor_rect, views::BubbleBorder::Arrow arrow, + ActivationAction activation_action, int string_specifier, - ActivationAction activation_action); + base::Optional<int> screenreader_string_specifier, + base::Optional<ui::Accelerator> feature_accelerator); // BubbleDialogDelegateView: int GetDialogButtons() const override; @@ -76,6 +70,8 @@ void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; gfx::Rect GetBubbleBounds() override; + ax::mojom::Role GetAccessibleWindowRole() const override; + base::string16 GetAccessibleWindowTitle() const override; void UpdateHighlightedButton(bool highlighted) override { // Do nothing: the anchor for promo bubbles should not highlight. } @@ -87,6 +83,8 @@ base::OneShotTimer timer_; const ActivationAction activation_action_; + base::string16 accessible_name_; + DISALLOW_COPY_AND_ASSIGN(FeaturePromoBubbleView); };
diff --git a/chrome/browser/ui/views/feature_promos/feature_promo_dialog_browsertest.cc b/chrome/browser/ui/views/feature_promos/feature_promo_dialog_browsertest.cc index ed7ef5d..3d02108b 100644 --- a/chrome/browser/ui/views/feature_promos/feature_promo_dialog_browsertest.cc +++ b/chrome/browser/ui/views/feature_promos/feature_promo_dialog_browsertest.cc
@@ -23,8 +23,8 @@ // currently no infrastructure for test-only string resources. int placeholder_string = IDS_NEWTAB_PROMO_0; FeaturePromoBubbleView::CreateOwned( - app_menu_button, views::BubbleBorder::TOP_RIGHT, placeholder_string, - FeaturePromoBubbleView::ActivationAction::ACTIVATE); + app_menu_button, views::BubbleBorder::TOP_RIGHT, + FeaturePromoBubbleView::ActivationAction::ACTIVATE, placeholder_string); } };
diff --git a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc index ce82d096..f7a6fd4d 100644 --- a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc +++ b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc
@@ -43,9 +43,15 @@ app_menu_button->AddObserver(this); app_menu_button->SetPromoFeature(InProductHelpFeature::kReopenTab); + // Get keyboard shortcut for reopening last closed tab. This should exist. + ui::Accelerator accelerator; + bool has_accelerator = + browser_view_->GetAccelerator(IDC_RESTORE_TAB, &accelerator); + DCHECK(has_accelerator); promo_bubble_ = FeaturePromoBubbleView::CreateOwned( app_menu_button, views::BubbleBorder::Arrow::TOP_RIGHT, - IDS_REOPEN_TAB_PROMO, FeaturePromoBubbleView::ActivationAction::ACTIVATE); + FeaturePromoBubbleView::ActivationAction::DO_NOT_ACTIVATE, + IDS_REOPEN_TAB_PROMO, IDS_REOPEN_TAB_PROMO_SCREENREADER, accelerator); promo_bubble_->set_close_on_deactivate(false); promo_bubble_->GetWidget()->AddObserver(this); } @@ -53,8 +59,18 @@ void ReopenTabPromoController::OnTabReopened(int command_id) { iph_service_->TabReopened(); - if (is_showing_ && command_id == AppMenuModel::kMinRecentTabsCommandId) { - promo_step_ = StepAtDismissal::kTabReopened; + if (!is_showing_) + return; + if (command_id != AppMenuModel::kMinRecentTabsCommandId && + command_id != IDC_RESTORE_TAB) + return; + + promo_step_ = StepAtDismissal::kTabReopened; + if (command_id == IDC_RESTORE_TAB) { + // If using the keyboard shortcut, we bypass the other steps and so we close + // the bubble now. + promo_bubble_->GetWidget()->Close(); + PromoEnded(); } } @@ -62,19 +78,20 @@ DCHECK(promo_bubble_); promo_bubble_ = nullptr; - // If the menu isn't showing, that means the promo bubble timed out. - if (!browser_view_->toolbar()->app_menu_button()->IsMenuShowing()) + // If we haven't progressed past |StepAtDismissal::kBubbleShown|, the bubble + // timed out without the user following our IPH. End it. + if (promo_step_ == StepAtDismissal::kBubbleShown) PromoEnded(); } void ReopenTabPromoController::AppMenuShown() { + promo_step_ = StepAtDismissal::kMenuOpened; + // Close the promo bubble since it doesn't automatically close on click. promo_bubble_->GetWidget()->Close(); // Stop showing promo on app menu button. browser_view_->toolbar()->app_menu_button()->SetPromoFeature(base::nullopt); - - promo_step_ = StepAtDismissal::kMenuOpened; } void ReopenTabPromoController::AppMenuClosed() {
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index 64d88fad..f2d3921 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -512,8 +512,11 @@ 0xFF); auto border = std::make_unique<views::BubbleBorder>( views::BubbleBorder::NONE, views::BubbleBorder::SMALL_SHADOW, bg_color); - border->SetCornerRadius( - ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH)); + // TODO(sajadm): Remove when fixing https://crbug.com/822075 and use + // EMPHASIS_HIGH metric values from the LayoutProvider to get the + // corner radius. + border->SetCornerRadius(2); + SetBackground(std::make_unique<views::BubbleBackground>(border.get())); SetBorder(std::move(border));
diff --git a/chrome/browser/ui/views/frame/browser_frame_mash.cc b/chrome/browser/ui/views/frame/browser_frame_mash.cc index 0536dcb..92eb1c3 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mash.cc +++ b/chrome/browser/ui/views/frame/browser_frame_mash.cc
@@ -88,6 +88,9 @@ std::unique_ptr<views::DesktopWindowTreeHostMus> desktop_window_tree_host = std::make_unique<views::DesktopWindowTreeHostMus>( std::move(window_tree_host_init_params), browser_frame_, this); + // BrowserNonClientFrameViewAsh::OnBoundsChanged() takes care of updating + // the insets. + desktop_window_tree_host->set_auto_update_client_area(false); SetDesktopWindowTreeHost(std::move(desktop_window_tree_host)); return params; }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 9147b20..1e52423 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -967,7 +967,7 @@ } } -void BrowserView::OnTabRestoredFromMenu(int command_id) { +void BrowserView::OnTabRestored(int command_id) { #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP) reopen_tab_promo_controller_.OnTabReopened(command_id); #endif
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 06aad03..55464d7d 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -316,7 +316,7 @@ int index, int reason) override; void OnTabDetached(content::WebContents* contents, bool was_active) override; - void OnTabRestoredFromMenu(int command_id) override; + void OnTabRestored(int command_id) override; void ZoomChangedForActiveTab(bool can_show_bubble) override; gfx::Rect GetRestoredBounds() const override; ui::WindowShowState GetRestoredState() const override;
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc index 687cf337..e44aa19bb 100644 --- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc +++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" @@ -53,6 +54,23 @@ return result; } + void set_manual_ack_dispatch_key_event_post_ime_callback(bool manual) { + manual_ack_dispatch_key_event_post_ime_callback_ = manual; + } + + void AckDispatchKeyEventPostIMECallback() { + DCHECK(manual_ack_dispatch_key_event_post_ime_callback_); + + if (!pending_dispatch_key_event_post_ime_callback_) { + pending_dispatch_key_event_post_ime_callback_wait_loop_ = + std::make_unique<base::RunLoop>(); + pending_dispatch_key_event_post_ime_callback_wait_loop_->Run(); + pending_dispatch_key_event_post_ime_callback_wait_loop_.reset(); + } + + std::move(pending_dispatch_key_event_post_ime_callback_).Run(false, false); + } + private: void SetCompositionText(const ui::CompositionText& composition) override { CompositionEvent ev = {CompositionEventType::SET, composition.text, 0}; @@ -89,6 +107,15 @@ void DispatchKeyEventPostIME( std::unique_ptr<ui::Event> event, DispatchKeyEventPostIMECallback callback) override { + if (manual_ack_dispatch_key_event_post_ime_callback_) { + // Only one pending callback is expected. + EXPECT_FALSE(pending_dispatch_key_event_post_ime_callback_); + pending_dispatch_key_event_post_ime_callback_ = std::move(callback); + if (pending_dispatch_key_event_post_ime_callback_wait_loop_) + pending_dispatch_key_event_post_ime_callback_wait_loop_->Quit(); + return; + } + std::move(callback).Run(false, false); } void EnsureCaretNotInRect(const gfx::Rect& rect) override {} @@ -103,6 +130,11 @@ std::unique_ptr<base::RunLoop> run_loop_; base::Optional<CompositionEvent> receieved_event_; + bool manual_ack_dispatch_key_event_post_ime_callback_ = false; + DispatchKeyEventPostIMECallback pending_dispatch_key_event_post_ime_callback_; + std::unique_ptr<base::RunLoop> + pending_dispatch_key_event_post_ime_callback_wait_loop_; + DISALLOW_COPY_AND_ASSIGN(TestTextInputClient); }; @@ -217,3 +249,27 @@ EXPECT_FALSE(ProcessKeyEvent(UnicodeKeyPress(ui::VKEY_V, ui::DomCode::US_V, ui::EF_CONTROL_DOWN, 'V'))); } + +// Test that multiple DispatchKeyEventPostIME calls are handled serially. +TEST_F(InputMethodBridgeChromeOSTest, SerialDispatchKeyEventPostIME) { + client_->set_manual_ack_dispatch_key_event_post_ime_callback(true); + + // Send multiple key events. + input_method_->ProcessKeyEvent( + std::make_unique<ui::KeyEvent>(ui::ET_KEY_PRESSED, ui::VKEY_A, + ui::EF_NONE), + base::DoNothing()); + input_method_->ProcessKeyEvent( + std::make_unique<ui::KeyEvent>(ui::ET_KEY_RELEASED, ui::VKEY_A, + ui::EF_NONE), + base::DoNothing()); + + // TestTextInputClient::DispatchKeyEventPostIME is called via mojo. + // RemoteTextInputClient should make the calls serially. Spin message loop to + // see whether |client_| complains about more than one call at a time. + base::RunLoop().RunUntilIdle(); + + // Ack the pending key events. + client_->AckDispatchKeyEventPostIMECallback(); + client_->AckDispatchKeyEventPostIMECallback(); +}
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc index a5653fc1..ef5b1599 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
@@ -4,17 +4,29 @@ #include "chrome/browser/ui/views/ime_driver/remote_text_input_client.h" +#include <memory> +#include <utility> + #include "base/bind.h" #include "base/bind_helpers.h" #include "ui/events/event_dispatcher.h" +struct RemoteTextInputClient::QueuedEvent { + QueuedEvent(std::unique_ptr<ui::Event> event, + DispatchKeyEventPostIMECallback callback) + : event(std::move(event)), callback(std::move(callback)) {} + + std::unique_ptr<ui::Event> event; + DispatchKeyEventPostIMECallback callback; +}; + RemoteTextInputClient::RemoteTextInputClient( ws::mojom::TextInputClientPtr client, ws::mojom::SessionDetailsPtr details) : remote_client_(std::move(client)), details_(std::move(details)) {} RemoteTextInputClient::~RemoteTextInputClient() { - while (!pending_callbacks_.empty()) { + while (!queued_events_.empty()) { RunNextPendingCallback(/* handled */ false, /* stopped_propagation */ false); } @@ -38,6 +50,7 @@ bool handled, bool stopped_propagation) { RunNextPendingCallback(handled, stopped_propagation); + DispatchQueuedEvent(); } void RemoteTextInputClient::SetCompositionText( @@ -201,20 +214,30 @@ ui::EventDispatchDetails RemoteTextInputClient::DispatchKeyEventPostIME( ui::KeyEvent* event, DispatchKeyEventPostIMECallback callback) { - pending_callbacks_.push(std::move(callback)); + const bool is_first_event = queued_events_.empty(); + queued_events_.emplace(ui::Event::Clone(*event), std::move(callback)); + if (is_first_event) + DispatchQueuedEvent(); + return ui::EventDispatchDetails(); +} + +void RemoteTextInputClient::DispatchQueuedEvent() { + if (queued_events_.empty()) + return; + + DCHECK(queued_events_.front().event); remote_client_->DispatchKeyEventPostIME( - ui::Event::Clone(*event), + std::move(queued_events_.front().event), base::BindOnce(&RemoteTextInputClient::OnDispatchKeyEventPostIMECompleted, weak_ptr_factory_.GetWeakPtr())); - return ui::EventDispatchDetails(); } void RemoteTextInputClient::RunNextPendingCallback(bool handled, bool stopped_propagation) { - DCHECK(!pending_callbacks_.empty()); + DCHECK(!queued_events_.empty()); DispatchKeyEventPostIMECallback callback = - std::move(pending_callbacks_.front()); - pending_callbacks_.pop(); + std::move(queued_events_.front().callback); + queued_events_.pop(); if (callback) std::move(callback).Run(handled, stopped_propagation); }
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h index e76bfcaf..75127adc 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
@@ -28,6 +28,8 @@ void SetTextInputClientData(ws::mojom::TextInputClientDataPtr data); private: + struct QueuedEvent; + // See |pending_callbacks_| for details. void OnDispatchKeyEventPostIMECompleted(bool handled, bool stopped_propagation); @@ -70,20 +72,25 @@ ui::KeyEvent* event, DispatchKeyEventPostIMECallback callback) override; - // Removes the callback at the front of |pending_callbacks_| and runs it with - // |handled| and |stopped_propagation| as arguments. + // Dispatches the first queued event. + void DispatchQueuedEvent(); + + // Removes the queue event at the front of |queued_events_| and runs its + // callback with |handled| and |stopped_propagation| as arguments. void RunNextPendingCallback(bool handled, bool stopped_propagation); ws::mojom::TextInputClientPtr remote_client_; ws::mojom::SessionDetailsPtr details_; - // Callbacks supplied to DispatchKeyEventPostIME() are added here. When the - // response from the remote side is received - // (OnDispatchKeyEventPostIMECompleted()), the callback is removed and run. - // This is done to ensure if we are destroyed all the callbacks are run. - // This is necessary as the callbacks may have originated from a remote - // client. - base::queue<DispatchKeyEventPostIMECallback> pending_callbacks_; + // Events to be dispatched with DispatchKeyEventPostIME(). Only one event is + // dispatched at a time and others are queued here until the current one + // finished processing, i.e. the response from the remote side is received + // (OnDispatchKeyEventPostIMECompleted()), the dispatched event is removed + // from the queue and its callback is invoked. This is done to avoid + // overlapping of key events processing (https://crbug.com/938808). + // Note that when we are destroyed all the callbacks needs to run. This is + // necessary as the callbacks may have originated from a remote client. + base::queue<QueuedEvent> queued_events_; base::WeakPtrFactory<RemoteTextInputClient> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc index 29be798dc..1481597 100644 --- a/chrome/browser/ui/views/location_bar/star_view.cc +++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -63,8 +63,8 @@ FeaturePromoBubbleView* bookmark_promo_bubble = FeaturePromoBubbleView::CreateOwned( this, views::BubbleBorder::TOP_RIGHT, - GetBookmarkPromoStringSpecifier(), - FeaturePromoBubbleView::ActivationAction::ACTIVATE); + FeaturePromoBubbleView::ActivationAction::ACTIVATE, + GetBookmarkPromoStringSpecifier()); if (!bookmark_promo_observer_.IsObserving( bookmark_promo_bubble->GetWidget())) { bookmark_promo_observer_.Add(bookmark_promo_bubble->GetWidget());
diff --git a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc index cbaed71..7d747da21 100644 --- a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc +++ b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
@@ -87,14 +87,14 @@ // First, fill the parent completely. SetBoundsRect(parent()->GetLocalBounds()); - // Then add two draggable views, each 10x2. + // Then add two draggable views, each 10x5. views::View* first = new TestDragView(); AddChildView(first); - first->SetBounds(2, 2, 10, 2); + first->SetBounds(2, 2, 10, 5); views::View* second = new TestDragView(); AddChildView(second); - second->SetBounds(15, 2, 10, 2); + second->SetBounds(15, 2, 10, 5); } bool TestTargetView::GetDropFormats( @@ -144,6 +144,8 @@ void BuildMenu(views::MenuItemView* menu) override; void DoTestWithMenuOpen() override; + virtual void OnDragEntered(); + TestTargetView* target_view() { return target_view_; } bool asked_to_close() const { return asked_to_close_; } bool performed_in_menu_drop() const { return performed_in_menu_drop_; } @@ -201,9 +203,9 @@ ASSERT_TRUE(submenu); ASSERT_TRUE(submenu->IsShowing()); ASSERT_EQ(3, submenu->GetMenuItemCount()); - views::View* first_view = submenu->GetMenuItemAt(0); + const views::View* first_view = submenu->GetMenuItemAt(0); ASSERT_EQ(1, first_view->child_count()); - views::View* child_view = first_view->child_at(0); + const views::View* child_view = first_view->child_at(0); EXPECT_EQ(child_view, target_view_); // We do this here (instead of in BuildMenu()) so that the menu is already @@ -211,6 +213,15 @@ target_view_->Init(); } +void MenuViewDragAndDropTest::OnDragEntered() { + // Drop the element. + GetDragTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseEvents), + ui_controls::LEFT, ui_controls::UP, + ui_controls::kNoAccelerator)); +} + bool MenuViewDragAndDropTest::GetDropFormats( views::MenuItemView* menu, int* formats, @@ -276,15 +287,16 @@ private: void StartDrag(); - void OnDragEntered(); }; void MenuViewDragAndDropTestTestInMenuDrag::OnWidgetDragWillStart() { // Enqueue an event to drag the second menu element to the third element. - views::View* drag_view = menu()->GetSubmenu()->GetMenuItemAt(2); - gfx::Point loc(1, drag_view->height() - 1); - views::View::ConvertPointToScreen(drag_view, &loc); - ScheduleMouseMoveInBackground(loc.x(), loc.y()); + const views::View* drop_target_view = menu()->GetSubmenu()->GetMenuItemAt(2); + const gfx::Point target = + ui_test_utils::GetCenterInScreenCoordinates(drop_target_view); + GetDragTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove), + target.x(), target.y())); } void MenuViewDragAndDropTestTestInMenuDrag::OnWidgetDragComplete() { @@ -303,8 +315,10 @@ void MenuViewDragAndDropTestTestInMenuDrag::DoTestWithMenuOpen() { MenuViewDragAndDropTest::DoTestWithMenuOpen(); + views::SubmenuView* submenu = menu()->GetSubmenu(); + // We're going to drag the second menu element. - views::MenuItemView* drag_view = menu()->GetSubmenu()->GetMenuItemAt(1); + views::MenuItemView* drag_view = submenu->GetMenuItemAt(1); ASSERT_NE(nullptr, drag_view); ui_test_utils::MoveMouseToCenterAndPress( drag_view, ui_controls::LEFT, ui_controls::DOWN, @@ -313,30 +327,17 @@ void MenuViewDragAndDropTestTestInMenuDrag::StartDrag() { // Begin dragging the second menu element. - views::View* drag_view = menu()->GetSubmenu()->GetMenuItemAt(2); - gfx::Point loc(1, drag_view->height() - 1); - views::View::ConvertPointToScreen(drag_view, &loc); + const views::View* drag_view = menu()->GetSubmenu()->GetMenuItemAt(1); + const gfx::Point current_position = + ui_test_utils::GetCenterInScreenCoordinates(drag_view); EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - loc.x() + 10, loc.y(), + current_position.x() + 10, current_position.y(), CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::OnDragEntered))); OnWidgetDragWillStart(); } -void MenuViewDragAndDropTestTestInMenuDrag::OnDragEntered() { - // Drop the item on the target. - views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2); - gfx::Point loc(1, drop_target->height() - 2); - views::View::ConvertPointToScreen(drop_target, &loc); - ui_controls::SendMouseMove(loc.x(), loc.y()); - - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::UP, - CreateEventTask( - this, &MenuViewDragAndDropTestTestInMenuDrag::OnWidgetDragComplete)); -} - // Test that an in-menu (i.e., entirely implemented in the menu code) closes the // menu automatically once the drag is complete, and does not ask the delegate // to stay open. @@ -356,18 +357,20 @@ protected: // MenuViewDragAndDropTest: void DoTestWithMenuOpen() override; + void OnDragEntered() override; private: void StartDrag(); - void OnDragEntered(); }; void MenuViewDragAndDropTestNestedDrag::OnWidgetDragWillStart() { // Enqueue an event to drag the target's first child to its second. - views::View* drop_target = target_view()->child_at(1); - gfx::Point loc(2, 0); - views::View::ConvertPointToScreen(drop_target, &loc); - ScheduleMouseMoveInBackground(loc.x(), loc.y()); + const views::View* drop_target_view = target_view()->child_at(1); + const gfx::Point target = + ui_test_utils::GetCenterInScreenCoordinates(drop_target_view); + GetDragTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove), + target.x(), target.y())); } void MenuViewDragAndDropTestNestedDrag::OnWidgetDragComplete() { @@ -402,33 +405,24 @@ CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::StartDrag)); } -void MenuViewDragAndDropTestNestedDrag::StartDrag() { - // Begin dragging the target's first child. - views::View* drop_target = target_view()->child_at(1); - gfx::Point loc(2, 0); - views::View::ConvertPointToScreen(drop_target, &loc); - EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( - loc.x() + 10, loc.y(), - CreateEventTask(this, - &MenuViewDragAndDropTestNestedDrag::OnDragEntered))); - - OnWidgetDragWillStart(); -} - void MenuViewDragAndDropTestNestedDrag::OnDragEntered() { // The view should be dragging now. EXPECT_TRUE(target_view()->dragging()); - // Drop the item so that it's now the second item. - views::View* drop_target = target_view()->child_at(1); - gfx::Point loc(5, 0); - views::View::ConvertPointToScreen(drop_target, &loc); - ui_controls::SendMouseMove(loc.x(), loc.y()); + MenuViewDragAndDropTest::OnDragEntered(); +} - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::UP, - CreateEventTask( - this, &MenuViewDragAndDropTestNestedDrag::OnWidgetDragComplete)); +void MenuViewDragAndDropTestNestedDrag::StartDrag() { + // Begin dragging the target's first child. + const views::View* drag_view = target_view()->child_at(0); + const gfx::Point current_position = + ui_test_utils::GetCenterInScreenCoordinates(drag_view); + EXPECT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( + current_position.x() + 10, current_position.y(), + CreateEventTask(this, + &MenuViewDragAndDropTestNestedDrag::OnDragEntered))); + + OnWidgetDragWillStart(); } // Test that a nested drag (i.e. one via a child view, and not entirely
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc index dfffc41..de918bf 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -73,7 +73,7 @@ #include "ui/views/window/dialog_client_view.h" #include "url/gurl.h" -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #endif @@ -902,7 +902,7 @@ permissions_set->AddPaddingColumn(views::GridLayout::kFixedSize, side_margin); } -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) std::unique_ptr<PageInfoUI::SecurityDescription> PageInfoBubbleView::CreateSecurityDescriptionForPasswordReuse( bool is_enterprise_password) const {
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.h b/chrome/browser/ui/views/page_info/page_info_bubble_view.h index c2ae099b..a39ffec 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view.h +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.h
@@ -143,7 +143,7 @@ bool is_list_empty, int column_id); -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) std::unique_ptr<PageInfoUI::SecurityDescription> CreateSecurityDescriptionForPasswordReuse( bool is_enterprise_password) const override;
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc index dd6be8a..e77a4d49 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -38,13 +38,10 @@ menu_width_(0), anchor_button_(anchor_button), close_bubble_helper_(this, browser) { - // Because the contents are in a ScrollView (see ShowView) they won't be - // clipped by the rounded corners like normal. To work around this, we add - // extra margins on the top and bottom so the scroll view is entirely - // inside the rectangular area of the bubble. - const int corner_radius = - ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH); - set_margins(gfx::Insets(corner_radius, 0, corner_radius, 0)); + // TODO(sajadm): Remove when fixing https://crbug.com/822075 + // The sign in webview will be clipped on the bottom corners without these + // margins, see related bug <http://crbug.com/593203>. + set_margins(gfx::Insets(0, 0, 2, 0)); if (anchor_button) { anchor_button->AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); } else { @@ -106,10 +103,7 @@ display::Screen::GetScreen() ->GetDisplayNearestPoint(anchor_rect.CenterPoint()) .work_area(); - const int top_margin = - ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH); - int available_space = - screen_space.bottom() - anchor_rect.bottom() - top_margin; + int available_space = screen_space.bottom() - anchor_rect.bottom(); #if defined(OS_WIN) // On Windows the bubble can also be show to the top of the anchor. available_space =
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc index b9e52a3..31aca8c 100644 --- a/chrome/browser/ui/views/tabs/new_tab_button.cc +++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/tabs/new_tab_button.h" +#include <memory> #include <string> #include "base/strings/string_number_conversions.h" @@ -101,8 +102,9 @@ DCHECK(!new_tab_promo_); // Owned by its native widget. Will be destroyed as its widget is destroyed. new_tab_promo_ = FeaturePromoBubbleView::CreateOwned( - this, views::BubbleBorder::LEFT_CENTER, GetNewTabPromoStringSpecifier(), - FeaturePromoBubbleView::ActivationAction::DO_NOT_ACTIVATE); + this, views::BubbleBorder::LEFT_CENTER, + FeaturePromoBubbleView::ActivationAction::DO_NOT_ACTIVATE, + GetNewTabPromoStringSpecifier()); new_tab_promo_observer_.Add(new_tab_promo_->GetWidget()); SchedulePaint(); }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 1935048..f1b44cb 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -970,6 +970,7 @@ AddMessageLoopObserver(); } + UpdateHoverCard(nullptr, false); controller_->CloseTab(model_index, source); } @@ -2250,7 +2251,7 @@ const SkColor inactive_fg = GetTabForegroundColor(TAB_INACTIVE, inactive_bg); // The contrast ratio for the separator between inactive tabs. - constexpr float kTabSeparatorContrast = 3.0f; + constexpr float kTabSeparatorContrast = 2.5f; const SkAlpha separator_alpha = get_alpha(inactive_fg, kTabSeparatorContrast); separator_color_ = color_utils::AlphaBlend(inactive_fg, inactive_bg, separator_alpha);
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc index 9096110d..d9a9d82 100644 --- a/chrome/browser/ui/views/task_manager_view.cc +++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -39,6 +39,7 @@ #include "chrome/grit/theme_resources.h" #include "ui/aura/client/aura_constants.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_features.h" #include "ui/gfx/image/image_skia.h" #endif // defined(OS_CHROMEOS) @@ -102,10 +103,16 @@ const ash::ShelfID shelf_id(kTaskManagerId); window->SetProperty(ash::kShelfIDKey, new std::string(shelf_id.Serialize())); window->SetProperty<int>(ash::kShelfItemTypeKey, ash::TYPE_DIALOG); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_ASH_SHELF_ICON_TASK_MANAGER); - // The new gfx::ImageSkia instance is owned by the window itself. - window->SetProperty(aura::client::kWindowIconKey, new gfx::ImageSkia(*icon)); + // For classic Ash, GetWindowIcon() is sufficient. For Mash, the task manager + // specifically needs to set a large app icon for the benefit of + // ShelfWindowWatcher. + if (features::IsUsingWindowService()) { + window->GetRootWindow()->SetProperty( + aura::client::kAppIconLargeKey, + new gfx::ImageSkia( + *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_ASH_SHELF_ICON_TASK_MANAGER))); + } #endif return g_task_manager_view->table_model_.get(); } @@ -183,6 +190,15 @@ return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_TITLE); } +gfx::ImageSkia TaskManagerView::GetWindowIcon() { +#if defined(OS_CHROMEOS) + return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_ASH_SHELF_ICON_TASK_MANAGER); +#else + return views::DialogDelegateView::GetWindowIcon(); +#endif +} + std::string TaskManagerView::GetWindowName() const { return prefs::kTaskManagerWindowPlacement; }
diff --git a/chrome/browser/ui/views/task_manager_view.h b/chrome/browser/ui/views/task_manager_view.h index bdd55e3..2213794 100644 --- a/chrome/browser/ui/views/task_manager_view.h +++ b/chrome/browser/ui/views/task_manager_view.h
@@ -60,6 +60,7 @@ bool CanMinimize() const override; bool ExecuteWindowsCommand(int command_id) override; base::string16 GetWindowTitle() const override; + gfx::ImageSkia GetWindowIcon() override; std::string GetWindowName() const override; bool Accept() override; bool Close() override;
diff --git a/chrome/browser/ui/views/test/view_event_test_base.cc b/chrome/browser/ui/views/test/view_event_test_base.cc index 24d2d07..0cc625e 100644 --- a/chrome/browser/ui/views/test/view_event_test_base.cc +++ b/chrome/browser/ui/views/test/view_event_test_base.cc
@@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/location.h" #include "base/macros.h" -#include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/ui/views/test/view_event_test_platform_part.h" #include "chrome/test/base/chrome_unit_test_suite.h" @@ -16,7 +15,6 @@ #include "mojo/core/embedder/embedder.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/ime/input_method_initializer.h" -#include "ui/base/test/ui_controls.h" #include "ui/compositor/test/context_factories_for_test.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -169,22 +167,17 @@ run_loop_.Run(); } -void ViewEventTestBase::ScheduleMouseMoveInBackground(int x, int y) { +scoped_refptr<base::SingleThreadTaskRunner> +ViewEventTestBase::GetDragTaskRunner() { if (!drag_event_thread_) { drag_event_thread_ = std::make_unique<base::Thread>("drag-event-thread"); drag_event_thread_->Start(); } - drag_event_thread_->task_runner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove), x, y)); -} - -void ViewEventTestBase::StopBackgroundThread() { - drag_event_thread_.reset(); + return drag_event_thread_->task_runner(); } void ViewEventTestBase::RunTestMethod(base::OnceClosure task) { - StopBackgroundThread(); + drag_event_thread_.reset(); std::move(task).Run(); if (HasFatalFailure())
diff --git a/chrome/browser/ui/views/test/view_event_test_base.h b/chrome/browser/ui/views/test/view_event_test_base.h index 4831f43..d18bed61 100644 --- a/chrome/browser/ui/views/test/view_event_test_base.h +++ b/chrome/browser/ui/views/test/view_event_test_base.h
@@ -62,16 +62,9 @@ // // Testing drag and drop is tricky because the mouse move that initiates drag // and drop may trigger a nested native event loop that waits for more mouse -// messages. Thus code needs an initial mouse move to start the drag, then a -// mouse move enqueued from a background thread to finish the drag (since tasks -// on the main thread may be stalled waiting for the nested loop to terminate). -// You can do this with a pattern like: -// // Schedule the mouse move at a location slightly different from where -// // you really want to move to to start the drag. -// ui_controls::SendMouseMoveNotifyWhenDone(loc.x + 10, loc.y, -// base::BindOnce(&YYY, this)); -// // Then schedule another mouse move to finish it. -// ScheduleMouseMoveInBackground(loc.x, loc.y); +// messages. Once a drag begins, all UI events until the drag ends must be +// driven from observer callbacks and posted on the task runner returned by +// GetDragTaskRunner(). class ViewEventTestBase : public views::WidgetDelegate, public testing::Test { public: @@ -123,15 +116,12 @@ base::BindOnce(method, base::Unretained(target))); } - // Spawns a new thread posts a MouseMove in the background. - void ScheduleMouseMoveInBackground(int x, int y); + // Returns a task runner to use for drag-related mouse events. + scoped_refptr<base::SingleThreadTaskRunner> GetDragTaskRunner(); views::Widget* window_; private: - // Stops the thread started by ScheduleMouseMoveInBackground. - void StopBackgroundThread(); - // Callback from CreateEventTask. Stops the background thread, runs the // supplied task and if there are failures invokes Done. void RunTestMethod(base::OnceClosure task);
diff --git a/chrome/browser/ui/views/test/view_event_test_platform_part_chromeos.cc b/chrome/browser/ui/views/test/view_event_test_platform_part_chromeos.cc index 1003a8d..ba0cd3cb 100644 --- a/chrome/browser/ui/views/test/view_event_test_platform_part_chromeos.cc +++ b/chrome/browser/ui/views/test/view_event_test_platform_part_chromeos.cc
@@ -92,6 +92,7 @@ chromeos::CrasAudioHandler::Shutdown(); bluez::BluezDBusManager::Shutdown(); chromeos::PowerPolicyController::Shutdown(); + chromeos::PowerManagerClient::Shutdown(); chromeos::DBusThreadManager::Shutdown(); }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc index 3534198..6d0b592 100644 --- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc +++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -79,10 +79,12 @@ public: PulsingInkDropMask(views::View* layer_container, const gfx::Size& layer_size, + const gfx::Insets& margins, float normal_corner_radius, float max_inset) : views::InkDropMask(layer_size), layer_container_(layer_container), + margins_(margins), normal_corner_radius_(normal_corner_radius), max_inset_(max_inset), throb_animation_(this) { @@ -101,6 +103,7 @@ ui::PaintRecorder recorder(context, layer()->size()); gfx::RectF bounds(layer()->bounds()); + bounds.Inset(margins_); const float current_inset = throb_animation_.CurrentValueBetween(0.0f, max_inset_); @@ -126,6 +129,11 @@ // our instance. views::View* const layer_container_; + // Margins between the layer bounds and the visible ink drop. We use this + // because sometimes the View we're masking is larger than the ink drop we + // want to show. + const gfx::Insets margins_; + // Normal corner radius of the ink drop without animation. This is also the // corner radius at the largest instant of the animation. const float normal_corner_radius_; @@ -394,10 +402,16 @@ const { #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP) if (promo_feature_) { - const float corner_radius = height() / 2.0f; + // This gets the latest ink drop insets. |SetTrailingMargin()| is called + // whenever our margins change (i.e. due to the window maximizing or + // minimizing) and updates our internal padding property accordingly. + const gfx::Insets ink_drop_insets = + GetToolbarInkDropInsets(this, *GetProperty(views::kInternalPaddingKey)); + const float corner_radius = + (height() - ink_drop_insets.top() - ink_drop_insets.bottom()) / 2.0f; return std::make_unique<PulsingInkDropMask>( - ink_drop_container(), ink_drop_container()->size(), corner_radius, - kFeaturePromoPulseInsetDip); + ink_drop_container(), ink_drop_container()->size(), ink_drop_insets, + corner_radius, kFeaturePromoPulseInsetDip); } #endif
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc index 7f09b01..a3b8179 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -97,7 +97,7 @@ void ToolbarViewInteractiveUITest::OnWidgetDragWillStart() { // Enqueue an event to move the mouse to the app menu button, which should - // result in calling OnMenuOpened(). + // result in calling AppMenuShown(). const gfx::Point target = ui_test_utils::GetCenterInScreenCoordinates(GetAppMenuButton()); task_runner_->PostTask( @@ -111,10 +111,12 @@ } void ToolbarViewInteractiveUITest::StartDrag() { - // Move the mouse outside the app button. - gfx::Point target = - ui_test_utils::GetCenterInScreenCoordinates(GetAppMenuButton()); - EXPECT_TRUE(ui_controls::SendMouseMove(target.x() + 10, target.y())); + // Move the mouse outside the toolbar action. + const views::View* toolbar_action = + GetBrowserActions()->GetToolbarActionViewAt(0); + gfx::Point target(toolbar_action->width() + 1, toolbar_action->height() / 2); + views::View::ConvertPointToScreen(toolbar_action, &target); + EXPECT_TRUE(ui_controls::SendMouseMove(target.x(), target.y())); OnWidgetDragWillStart(); }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 14811cf7..18a0cd2 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -226,7 +226,7 @@ #include "extensions/common/manifest.h" #endif -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #include "chrome/browser/ui/webui/reset_password/reset_password_ui.h" #include "components/safe_browsing/features.h" @@ -687,7 +687,7 @@ return &NewWebUI<MediaEngagementUI>; } -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) bool enable_reset_password = base::FeatureList::IsEnabled( safe_browsing::kForceEnableResetPasswordWebUI) ||
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc index 85c395c..9e43838 100644 --- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -217,7 +217,6 @@ AddCallback("toggleResetScreen", &CoreOobeHandler::HandleToggleResetScreen); AddCallback("toggleEnableDebuggingScreen", &CoreOobeHandler::HandleEnableDebuggingScreen); - AddCallback("headerBarVisible", &CoreOobeHandler::HandleHeaderBarVisible); AddCallback("raiseTabKeyEvent", &CoreOobeHandler::HandleRaiseTabKeyEvent); // Note: Used by enterprise_RemoraRequisitionDisplayUsage.py: // TODO(felixe): Use chrome.system.display or cros_display_config.mojom, @@ -303,10 +302,6 @@ CallJS("cr.ui.Oobe.reloadEulaContent", dictionary); } -void CoreOobeHandler::ShowControlBar(bool show) { - CallJS("cr.ui.Oobe.showControlBar", show); -} - void CoreOobeHandler::SetVirtualKeyboardShown(bool shown) { CallJS("cr.ui.Oobe.setVirtualKeyboardShown", shown); } @@ -479,11 +474,6 @@ UpdateOobeUIVisibility(); } -void CoreOobeHandler::UpdateShutdownAndRebootVisibility( - bool reboot_on_shutdown) { - CallJS("cr.ui.Oobe.showShutdown", !reboot_on_shutdown); -} - void CoreOobeHandler::SetLoginUserCount(int user_count) { CallJS("cr.ui.Oobe.setLoginUserCount", user_count); } @@ -584,7 +574,6 @@ if (!features::IsUsingWindowService()) { const bool is_keyboard_shown = ChromeKeyboardControllerClient::Get()->is_keyboard_visible(); - ShowControlBar(!is_keyboard_shown); SetVirtualKeyboardShown(is_keyboard_shown); } } @@ -623,12 +612,6 @@ static_cast<HelpAppLauncher::HelpTopic>(help_topic_id)); } -void CoreOobeHandler::HandleHeaderBarVisible() { - LoginDisplayHost* login_display_host = LoginDisplayHost::default_host(); - if (login_display_host) - login_display_host->SetStatusAreaVisible(true); -} - void CoreOobeHandler::HandleRaiseTabKeyEvent(bool reverse) { ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE); if (reverse)
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h index 324e0f93..67fe9508 100644 --- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
@@ -104,7 +104,6 @@ void ClearErrors() override; void ReloadContent(const base::DictionaryValue& dictionary) override; void ReloadEulaContent(const base::DictionaryValue& dictionary) override; - void ShowControlBar(bool show) override; void SetVirtualKeyboardShown(bool displayed) override; void SetClientAreaSize(int width, int height) override; void ShowDeviceResetScreen() override; @@ -140,7 +139,6 @@ void HandleLaunchHelpApp(double help_topic_id); void HandleToggleResetScreen(); void HandleEnableDebuggingScreen(); - void HandleHeaderBarVisible(); void HandleSetOobeBootstrappingSlave(); void HandleGetPrimaryDisplayNameForTesting(const base::ListValue* args); void GetPrimaryDisplayNameCallback(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 7c5fd013..55f15d3 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -185,14 +185,6 @@ // nosignup flow if new users are not allowed. if (!allow_new_user || is_restrictive_proxy) params->SetString("flow", "nosignup"); - - params->SetBoolean("supervisedUsersCanCreate", false); - - // Now check whether we're in multi-profiles user adding scenario and - // disable GAIA right panel features if that's the case. - if (UserAddingScreen::Get()->IsRunning()) { - params->SetBoolean("supervisedUsersCanCreate", false); - } } void RecordSAMLScrapingVerificationResultInHistogram(bool success) { @@ -1203,7 +1195,7 @@ LoadAuthExtension(!gaia_silent_load_ /* force */, false /* offline */); signin_screen_handler_->UpdateUIState( - SigninScreenHandler::UI_STATE_GAIA_SIGNIN, nullptr); + SigninScreenHandler::UI_STATE_GAIA_SIGNIN); core_oobe_view_->UpdateKeyboardState(); if (gaia_silent_load_) {
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc deleted file mode 100644 index f0dee83..0000000 --- a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc +++ /dev/null
@@ -1,216 +0,0 @@ -// Copyright 2013 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/webui/chromeos/login/kiosk_app_menu_handler.h" - -#include <stddef.h> - -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/system/sys_info.h" -#include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" -#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" -#include "chrome/browser/chromeos/login/existing_user_controller.h" -#include "chrome/browser/chromeos/login/screens/network_error.h" -#include "chrome/grit/generated_resources.h" -#include "chromeos/constants/chromeos_switches.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/web_ui.h" -#include "extensions/grit/extensions_browser_resources.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/webui/web_ui_util.h" - -namespace chromeos { - -namespace { - -// JS functions that define new and old kiosk UI API. -const char kKioskSetAppsNewAPI[] = "login.AccountPickerScreen.setApps"; -const char kKioskSetAppsOldAPI[] = "login.AppsMenuButton.setApps"; -const char kKioskShowErrorNewAPI[] = "login.AccountPickerScreen.showAppError"; -const char kKioskShowErrorOldAPI[] = "login.AppsMenuButton.showError"; - -} // namespace - -KioskAppMenuHandler::KioskAppMenuHandler( - const scoped_refptr<NetworkStateInformer>& network_state_informer) - : is_webui_initialized_(false), - network_state_informer_(network_state_informer), - weak_ptr_factory_(this) { - KioskAppManager::Get()->AddObserver(this); - network_state_informer_->AddObserver(this); - ArcKioskAppManager::Get()->AddObserver(this); -} - -KioskAppMenuHandler::~KioskAppMenuHandler() { - KioskAppManager::Get()->RemoveObserver(this); - network_state_informer_->RemoveObserver(this); - ArcKioskAppManager::Get()->RemoveObserver(this); -} - -void KioskAppMenuHandler::GetLocalizedStrings( - base::DictionaryValue* localized_strings) { - localized_strings->SetString( - "showApps", - l10n_util::GetStringUTF16(IDS_KIOSK_APPS_BUTTON)); - localized_strings->SetString( - "confirmKioskAppDiagnosticModeFormat", - l10n_util::GetStringUTF16(IDS_LOGIN_CONFIRM_KIOSK_DIAGNOSTIC_FORMAT)); - localized_strings->SetString( - "confirmKioskAppDiagnosticModeYes", - l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)); - localized_strings->SetString( - "confirmKioskAppDiagnosticModeNo", - l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)); - localized_strings->SetBoolean( - "kioskAppHasLaunchError", - KioskAppLaunchError::Get() != KioskAppLaunchError::NONE); -} - -void KioskAppMenuHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "initializeKioskApps", - base::BindRepeating(&KioskAppMenuHandler::HandleInitializeKioskApps, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "kioskAppsLoaded", - base::BindRepeating(&KioskAppMenuHandler::HandleKioskAppsLoaded, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "checkKioskAppLaunchError", - base::BindRepeating(&KioskAppMenuHandler::HandleCheckKioskAppLaunchError, - base::Unretained(this))); -} - -// static -bool KioskAppMenuHandler::EnableNewKioskUI() { - // Turn off new kiosk UI for M34/35. - // TODO(xiyuan, nkostylev): Revist for http://crbug.com/362062. - return false; -} - -void KioskAppMenuHandler::SendKioskApps() { - if (!is_webui_initialized_) - return; - - KioskAppManager::Apps apps; - KioskAppManager::Get()->GetApps(&apps); - - base::ListValue apps_list; - for (size_t i = 0; i < apps.size(); ++i) { - const KioskAppManager::App& app_data = apps[i]; - - std::unique_ptr<base::DictionaryValue> app_info( - new base::DictionaryValue()); - app_info->SetBoolean("isApp", true); - app_info->SetString("id", app_data.app_id); - app_info->SetBoolean("isAndroidApp", false); - // Unused for native apps. Added for consistency with Android apps. - app_info->SetString("account_email", app_data.account_id.GetUserEmail()); - app_info->SetString("label", app_data.name); - - std::string icon_url; - if (app_data.icon.isNull()) { - icon_url = - webui::GetBitmapDataUrl(*ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_APP_DEFAULT_ICON) - .ToSkBitmap()); - } else { - icon_url = webui::GetBitmapDataUrl(*app_data.icon.bitmap()); - } - app_info->SetString("iconUrl", icon_url); - - apps_list.Append(std::move(app_info)); - } - - ArcKioskAppManager::Apps arc_apps; - ArcKioskAppManager::Get()->GetAllApps(&arc_apps); - for (size_t i = 0; i < arc_apps.size(); ++i) { - std::unique_ptr<base::DictionaryValue> app_info( - new base::DictionaryValue()); - app_info->SetBoolean("isApp", true); - app_info->SetBoolean("isAndroidApp", true); - app_info->SetString("id", arc_apps[i]->app_id()); - app_info->SetString("account_email", - arc_apps[i]->account_id().GetUserEmail()); - app_info->SetString("label", arc_apps[i]->name()); - - std::string icon_url; - if (arc_apps[i]->icon().isNull()) { - icon_url = - webui::GetBitmapDataUrl(*ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_APP_DEFAULT_ICON) - .ToSkBitmap()); - } else { - icon_url = webui::GetBitmapDataUrl(*arc_apps[i]->icon().bitmap()); - } - app_info->SetString("iconUrl", icon_url); - - apps_list.Append(std::move(app_info)); - } - - web_ui()->CallJavascriptFunctionUnsafe( - EnableNewKioskUI() ? kKioskSetAppsNewAPI : kKioskSetAppsOldAPI, - apps_list); -} - -void KioskAppMenuHandler::HandleInitializeKioskApps( - const base::ListValue* args) { - is_webui_initialized_ = true; - SendKioskApps(); - UpdateState(NetworkError::ERROR_REASON_UPDATE); -} - -void KioskAppMenuHandler::HandleKioskAppsLoaded( - const base::ListValue* args) { - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_KIOSK_APPS_LOADED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); -} - -void KioskAppMenuHandler::HandleCheckKioskAppLaunchError( - const base::ListValue* args) { - KioskAppLaunchError::Error error = KioskAppLaunchError::Get(); - if (error == KioskAppLaunchError::NONE) - return; - KioskAppLaunchError::RecordMetricAndClear(); - - const std::string error_message = KioskAppLaunchError::GetErrorMessage(error); - bool new_kiosk_ui = EnableNewKioskUI(); - web_ui()->CallJavascriptFunctionUnsafe( - new_kiosk_ui ? kKioskShowErrorNewAPI : kKioskShowErrorOldAPI, - base::Value(error_message)); -} - -void KioskAppMenuHandler::OnKioskAppsSettingsChanged() { - SendKioskApps(); -} - -void KioskAppMenuHandler::OnKioskAppDataChanged(const std::string& app_id) { - SendKioskApps(); -} - -void KioskAppMenuHandler::OnKioskAppDataLoadFailure(const std::string& app_id) { - SendKioskApps(); -} - -void KioskAppMenuHandler::UpdateState(NetworkError::ErrorReason reason) { - if (network_state_informer_->state() == NetworkStateInformer::ONLINE) - KioskAppManager::Get()->RetryFailedAppDataFetch(); -} - -void KioskAppMenuHandler::OnArcKioskAppsChanged() { - SendKioskApps(); -} - -} // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h deleted file mode 100644 index ce1e547..0000000 --- a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2013 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_CHROMEOS_LOGIN_KIOSK_APP_MENU_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_APP_MENU_HANDLER_H_ - -#include <memory> -#include <string> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" -#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" -#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" -#include "chrome/browser/chromeos/login/screens/network_error.h" -#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" -#include "content/public/browser/web_ui_message_handler.h" - -namespace chromeos { - -// KioskAppMenuHandler supplies kiosk apps data to apps menu on sign-in -// screen when app mode is enabled and handles "launchKioskApp" request -// from the apps menu. -class KioskAppMenuHandler - : public content::WebUIMessageHandler, - public KioskAppManagerObserver, - public NetworkStateInformer::NetworkStateInformerObserver, - public ArcKioskAppManager::ArcKioskAppManagerObserver { - public: - explicit KioskAppMenuHandler( - const scoped_refptr<NetworkStateInformer>& network_state_informer); - ~KioskAppMenuHandler() override; - - void GetLocalizedStrings(base::DictionaryValue* localized_strings); - - // content::WebUIMessageHandler overrides: - void RegisterMessages() override; - - // Returns true if new kiosk UI is enabled. - static bool EnableNewKioskUI(); - - private: - // Sends all kiosk apps to webui. - void SendKioskApps(); - - // JS callbacks. - void HandleInitializeKioskApps(const base::ListValue* args); - void HandleKioskAppsLoaded(const base::ListValue* args); - void HandleCheckKioskAppLaunchError(const base::ListValue* args); - - // KioskAppManagerObserver overrides: - void OnKioskAppsSettingsChanged() override; - void OnKioskAppDataChanged(const std::string& app_id) override; - void OnKioskAppDataLoadFailure(const std::string& app_id) override; - - // NetworkStateInformer::NetworkStateInformerObserver overrides: - void UpdateState(NetworkError::ErrorReason reason) override; - - // ArcKioskAppManager::ArcKioskAppManagerObserver overrides: - void OnArcKioskAppsChanged() override; - - // True when WebUI is initialized. Otherwise don't allow calling JS functions. - bool is_webui_initialized_; - - scoped_refptr<NetworkStateInformer> network_state_informer_; - - base::WeakPtrFactory<KioskAppMenuHandler> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(KioskAppMenuHandler); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_APP_MENU_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/l10n_util_unittest.cc b/chrome/browser/ui/webui/chromeos/login/l10n_util_unittest.cc index b761ce9..46a99135 100644 --- a/chrome/browser/ui/webui/chromeos/login/l10n_util_unittest.cc +++ b/chrome/browser/ui/webui/chromeos/login/l10n_util_unittest.cc
@@ -75,6 +75,7 @@ } L10nUtilTest::~L10nUtilTest() { + chromeos::system::StatisticsProvider::GetInstance()->Shutdown(); chromeos::input_method::Shutdown(); }
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index 2cbdfee..d703c19 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -59,7 +59,6 @@ #include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h" #include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h" @@ -457,12 +456,6 @@ AddScreenHandler(std::make_unique<MultiDeviceSetupScreenHandler>( js_calls_container_.get())); - // Initialize KioskAppMenuHandler. Note that it is NOT a screen handler. - auto kiosk_app_menu_handler = - std::make_unique<KioskAppMenuHandler>(network_state_informer_); - kiosk_app_menu_handler_ = kiosk_app_menu_handler.get(); - web_ui()->AddMessageHandler(std::move(kiosk_app_menu_handler)); - Profile* profile = Profile::FromWebUI(web_ui()); // Set up the chrome://theme/ source, for Chrome logo. content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile)); @@ -681,10 +674,6 @@ return GetView<NetworkScreenHandler>(); } -void OobeUI::OnShutdownPolicyChanged(bool reboot_on_shutdown) { - core_handler_->UpdateShutdownAndRebootVisibility(reboot_on_shutdown); -} - AppLaunchSplashScreenView* OobeUI::GetAppLaunchSplashScreenView() { return GetView<AppLaunchSplashScreenHandler>(); } @@ -702,7 +691,6 @@ handler->GetLocalizedStrings(localized_strings); const std::string& app_locale = g_browser_process->GetApplicationLocale(); webui::SetLoadTimeDataDefaults(app_locale, localized_strings); - kiosk_app_menu_handler_->GetLocalizedStrings(localized_strings); #if defined(GOOGLE_CHROME_BUILD) localized_strings->SetString("buildType", "chrome"); @@ -715,8 +703,6 @@ localized_strings->SetString("highlightStrength", keyboard_driven_oobe ? "strong" : "normal"); - bool new_kiosk_ui = KioskAppMenuHandler::EnableNewKioskUI(); - localized_strings->SetString("newKioskUI", new_kiosk_ui ? "on" : "off"); localized_strings->SetString( "showViewsLock", ash::switches::IsUsingViewsLock() ? "on" : "off"); localized_strings->SetString( @@ -758,13 +744,6 @@ ScreenInitialized(handler->oobe_screen()); } } - - // Instantiate the ShutdownPolicyHandler. - shutdown_policy_handler_.reset( - new ShutdownPolicyHandler(CrosSettings::Get(), this)); - - // Trigger an initial update. - shutdown_policy_handler_->NotifyDelegateWithShutdownPolicy(); } void OobeUI::CurrentScreenChanged(OobeScreen new_screen) {
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h index 9c111fd..ba071a8 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -15,7 +15,6 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "chrome/browser/chromeos/login/oobe_screen.h" -#include "chrome/browser/chromeos/settings/shutdown_policy_handler.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h" #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" @@ -50,7 +49,6 @@ class FingerprintSetupScreenView; class GaiaView; class HIDDetectionView; -class KioskAppMenuHandler; class KioskAutolaunchScreenView; class KioskEnableScreenView; class LoginScreenContext; @@ -78,8 +76,7 @@ // - welcome screen (setup language/keyboard/network). // - eula screen (CrOS (+ OEM) EULA content/TPM password/crash reporting). // - update screen. -class OobeUI : public ui::MojoWebUIController, - public ShutdownPolicyHandler::Delegate { +class OobeUI : public ui::MojoWebUIController { public: // List of known types of OobeUI. Type added as path in chrome://oobe url, for // example chrome://oobe/user-adding. @@ -144,9 +141,6 @@ NetworkScreenView* GetNetworkScreenView(); MarketingOptInScreenView* GetMarketingOptInScreenView(); - // ShutdownPolicyHandler::Delegate - void OnShutdownPolicyChanged(bool reboot_on_shutdown) override; - // Collects localized strings from the owned handlers. void GetLocalizedStrings(base::DictionaryValue* localized_strings); @@ -252,9 +246,6 @@ std::vector<BaseWebUIHandler*> webui_only_handlers_; // Non-owning pointers. std::vector<BaseScreenHandler*> screen_handlers_; // Non-owning pointers. - KioskAppMenuHandler* kiosk_app_menu_handler_ = - nullptr; // Non-owning pointers. - std::unique_ptr<ErrorScreen> error_screen_; // Id of the current oobe/login screen. @@ -273,9 +264,6 @@ // List of registered observers. base::ObserverList<Observer>::Unchecked observer_list_; - // Observer of CrosSettings watching the kRebootOnShutdown policy. - std::unique_ptr<ShutdownPolicyHandler> shutdown_policy_handler_; - std::unique_ptr<OobeDisplayChooser> oobe_display_chooser_; // Store the deferred JS calls before the screen handler instance is
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 1f0c887c..713eb50 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -12,8 +12,6 @@ #include "ash/public/cpp/login_constants.h" #include "ash/public/cpp/wallpaper_types.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shutdown.mojom.h" #include "ash/public/interfaces/tray_action.mojom.h" #include "base/bind.h" #include "base/i18n/number_formatting.h" @@ -102,9 +100,7 @@ #include "components/version_info/version_info.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/service_manager_connection.h" #include "google_apis/gaia/gaia_auth_util.h" -#include "services/service_manager/public/cpp/connector.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/ime/chromeos/ime_keyboard.h" #include "ui/base/ime/chromeos/input_method_descriptor.h" @@ -326,14 +322,6 @@ builder->Add("submitButtonAccessibleName", IDS_LOGIN_POD_SUBMIT_BUTTON_ACCESSIBLE_NAME); builder->Add("signedIn", IDS_SCREEN_LOCK_ACTIVE_USER); - builder->Add("launchAppButton", IDS_LAUNCH_APP_BUTTON); - builder->Add("restart", IDS_ASH_SHELF_RESTART_BUTTON); - builder->Add("shutDown", IDS_ASH_SHELF_SHUTDOWN_BUTTON); - builder->Add("addUser", IDS_ASH_ADD_USER_BUTTON); - builder->Add("browseAsGuest", IDS_ASH_BROWSE_AS_GUEST_BUTTON); - builder->Add("moreOptions", IDS_MORE_OPTIONS_BUTTON); - builder->Add("cancel", IDS_ASH_SHELF_CANCEL_BUTTON); - builder->Add("signOutUser", IDS_ASH_SHELF_SIGN_OUT_BUTTON); builder->Add("offlineLogin", IDS_OFFLINE_LOGIN_HTML); builder->Add("ownerUserPattern", IDS_LOGIN_POD_OWNER_USER); builder->Add("removeUser", IDS_LOGIN_POD_REMOVE_USER); @@ -460,7 +448,6 @@ &SigninScreenHandler::HandleLaunchPublicSession); AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin); AddCallback("rebootSystem", &SigninScreenHandler::HandleRebootSystem); - AddCallback("shutdownSystem", &SigninScreenHandler::HandleShutdownSystem); AddCallback("removeUser", &SigninScreenHandler::HandleRemoveUser); AddCallback("toggleEnrollmentScreen", &SigninScreenHandler::HandleToggleEnrollmentScreen); @@ -470,7 +457,6 @@ &SigninScreenHandler::HandleToggleKioskEnableScreen); AddCallback("accountPickerReady", &SigninScreenHandler::HandleAccountPickerReady); - AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser); AddCallback("openInternetDetailDialog", &SigninScreenHandler::HandleOpenInternetDetailDialog); AddCallback("loginVisible", &SigninScreenHandler::HandleLoginVisible); @@ -499,12 +485,6 @@ AddCallback("sendFeedback", &SigninScreenHandler::HandleSendFeedback); AddCallback("sendFeedbackAndResyncUserData", &SigninScreenHandler::HandleSendFeedbackAndResyncUserData); - - // This message is sent by the kiosk app menu, but is handled here - // so we can tell the delegate to launch the app. - AddCallback("launchKioskApp", &SigninScreenHandler::HandleLaunchKioskApp); - AddCallback("launchArcKioskApp", - &SigninScreenHandler::HandleLaunchArcKioskApp); } void SigninScreenHandler::Show(const LoginScreenContext& context, @@ -592,23 +572,20 @@ ->GetImeKeyboard() ->SetCapsLockEnabled(false); - base::DictionaryValue params; - params.SetBoolean("disableAddUser", AllWhitelistedUsersPresent()); - UpdateUIState(UI_STATE_ACCOUNT_PICKER, ¶ms); + UpdateUIState(UI_STATE_ACCOUNT_PICKER); } } -void SigninScreenHandler::UpdateUIState(UIState ui_state, - base::DictionaryValue* params) { +void SigninScreenHandler::UpdateUIState(UIState ui_state) { switch (ui_state) { case UI_STATE_GAIA_SIGNIN: ui_state_ = UI_STATE_GAIA_SIGNIN; - ShowScreenWithData(OobeScreen::SCREEN_GAIA_SIGNIN, params); + ShowScreen(OobeScreen::SCREEN_GAIA_SIGNIN); break; case UI_STATE_ACCOUNT_PICKER: ui_state_ = UI_STATE_ACCOUNT_PICKER; gaia_screen_handler_->CancelShowGaiaAsync(); - ShowScreenWithData(OobeScreen::SCREEN_ACCOUNT_PICKER, params); + ShowScreen(OobeScreen::SCREEN_ACCOUNT_PICKER); break; default: NOTREACHED(); @@ -967,8 +944,7 @@ // We need to reload GAIA if UI_STATE_UNKNOWN or the allow new user setting // has changed so that reloaded GAIA shows/hides the option to create a new // account. - UpdateUIState(UI_STATE_ACCOUNT_PICKER, nullptr); - UpdateAddButtonStatus(); + UpdateUIState(UI_STATE_ACCOUNT_PICKER); } } @@ -1074,11 +1050,6 @@ is_account_picker_showing_first_time_; } -void SigninScreenHandler::UpdateAddButtonStatus() { - CallJS("cr.ui.login.DisplayManager.updateAddUserButtonStatus", - AllWhitelistedUsersPresent()); -} - void SigninScreenHandler::HandleAuthenticateUser(const AccountId& account_id, const std::string& password, bool authenticated_by_pin) { @@ -1178,16 +1149,7 @@ gaia_screen_handler_->set_populated_email(email); gaia_screen_handler_->LoadAuthExtension(true /* force */, true /* offline */); - UpdateUIState(UI_STATE_GAIA_SIGNIN, nullptr); -} - -void SigninScreenHandler::HandleShutdownSystem() { - ash::mojom::ShutdownControllerPtr shutdown_controller; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shutdown_controller); - - shutdown_controller->RequestShutdownFromLoginScreen(); + UpdateUIState(UI_STATE_GAIA_SIGNIN); } void SigninScreenHandler::HandleRebootSystem() { @@ -1207,7 +1169,6 @@ if (!delegate_) return; delegate_->RemoveUser(account_id); - UpdateAddButtonStatus(); } void SigninScreenHandler::HandleToggleEnrollmentScreen() { @@ -1239,8 +1200,7 @@ void SigninScreenHandler::LoadUsers(const user_manager::UserList& users, const base::ListValue& users_list) { - CallJS("login.AccountPickerScreen.loadUsers", users_list, - delegate_->IsShowGuest()); + CallJS("login.AccountPickerScreen.loadUsers", users_list); // Enable pin for any users who can use it. // TODO(jdufault): Cache pin state in BrowserProcess::local_state() so we @@ -1299,11 +1259,6 @@ delegate_->OnSigninScreenReady(); } -void SigninScreenHandler::HandleSignOutUser() { - if (delegate_) - delegate_->Signout(); -} - void SigninScreenHandler::HandleOpenInternetDetailDialog() { // Empty string opens the internet detail dialog for the default network. InternetDetailDialog::ShowDialog(""); @@ -1439,22 +1394,6 @@ account_id, locale, *keyboard_layouts); } -void SigninScreenHandler::HandleLaunchKioskApp(const AccountId& app_account_id, - bool diagnostic_mode) { - UserContext context(user_manager::USER_TYPE_KIOSK_APP, app_account_id); - SigninSpecifics specifics; - specifics.kiosk_diagnostic_mode = diagnostic_mode; - if (delegate_) - delegate_->Login(context, specifics); -} - -void SigninScreenHandler::HandleLaunchArcKioskApp( - const AccountId& app_account_id) { - UserContext context(user_manager::USER_TYPE_ARC_KIOSK_APP, app_account_id); - if (delegate_) - delegate_->Login(context, SigninSpecifics()); -} - void SigninScreenHandler::HandleGetTabletModeState() { CallJS("login.AccountPickerScreen.setTabletModeState", TabletModeClient::Get()->tablet_mode_enabled());
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index ef9db6ff..622c34da 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -47,7 +47,6 @@ } // namespace ash namespace base { -class DictionaryValue; class ListValue; } @@ -261,9 +260,8 @@ void ShowImpl(); // Updates current UI of the signin screen according to |ui_state| - // argument. Optionally it can pass screen initialization data via - // |params| argument. - void UpdateUIState(UIState ui_state, base::DictionaryValue* params); + // argument. + void UpdateUIState(UIState ui_state); void UpdateStateInternal(NetworkError::ErrorReason reason, bool force_update); void SetupAndShowOfflineMessage(NetworkStateInformer::State state, @@ -313,8 +311,6 @@ // TabletModeClientObserver: void OnTabletModeToggled(bool enabled) override; - void UpdateAddButtonStatus(); - // Restore input focus to current user pod. void RefocusCurrentPod(); @@ -338,7 +334,6 @@ const std::string& locale, const std::string& input_method); void HandleOfflineLogin(const base::ListValue* args); - void HandleShutdownSystem(); void HandleRebootSystem(); void HandleRemoveUser(const AccountId& account_id); void HandleToggleEnrollmentScreen(); @@ -348,7 +343,6 @@ void HandleToggleResetScreen(); void HandleToggleKioskAutolaunchScreen(); void HandleAccountPickerReady(); - void HandleSignOutUser(); void HandleOpenInternetDetailDialog(); void HandleLoginVisible(const std::string& source); void HandleCancelPasswordChangedFlow(const AccountId& account_id);
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom index 35f6b28..aa46669 100644 --- a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom +++ b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
@@ -35,6 +35,24 @@ Time? refresh_suppress_time; }; +// Models a single suggestion in the Feed. +struct Suggestion { + // Title of the suggestion. + string title; + + // URL of the suggested page. + string url; + + // Name of the content's publisher. + string publisher_name; + + // URL of the image associated with the suggestion. + string image_url; + + // URL of the suggested page's favicon. + string favicon_url; +}; + // Time wrapper to allow for nullable objects. struct Time { double ms_since_epoch; @@ -58,4 +76,7 @@ // Clear all data cached by the Feed library. Also triggers a refresh of the // Feed. ClearCachedDataAndRefreshFeed(); + + // Get the last known content with metadata. + GetCurrentContent() => (array<Suggestion> suggestions); };
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc index f8075e5..d1601c3 100644 --- a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc +++ b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc
@@ -10,10 +10,12 @@ #include "base/time/time.h" #include "chrome/browser/android/feed/feed_lifecycle_bridge.h" #include "components/feed/content/feed_host_service.h" +#include "components/feed/content/feed_offline_host.h" #include "components/feed/core/feed_scheduler_host.h" #include "components/feed/core/pref_names.h" #include "components/feed/core/user_classifier.h" #include "components/feed/feed_feature_list.h" +#include "components/offline_pages/core/prefetch/suggestions_provider.h" #include "components/prefs/pref_service.h" namespace { @@ -31,7 +33,9 @@ PrefService* pref_service) : binding_(this, std::move(request)), feed_scheduler_host_(feed_host_service->GetSchedulerHost()), - pref_service_(pref_service) {} + feed_offline_host_(feed_host_service->GetOfflineHost()), + pref_service_(pref_service), + weak_ptr_factory_(this) {} FeedInternalsPageHandler::~FeedInternalsPageHandler() = default; @@ -84,3 +88,29 @@ void FeedInternalsPageHandler::ClearCachedDataAndRefreshFeed() { feed::FeedLifecycleBridge::ClearCachedData(); } + +void FeedInternalsPageHandler::GetCurrentContent( + GetCurrentContentCallback callback) { + feed_offline_host_->GetCurrentArticleSuggestions(base::BindOnce( + &FeedInternalsPageHandler::OnGetCurrentArticleSuggestionsDone, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void FeedInternalsPageHandler::OnGetCurrentArticleSuggestionsDone( + GetCurrentContentCallback callback, + std::vector<offline_pages::PrefetchSuggestion> results) { + std::vector<feed_internals::mojom::SuggestionPtr> suggestions; + + for (offline_pages::PrefetchSuggestion result : results) { + auto suggestion = feed_internals::mojom::Suggestion::New(); + suggestion->title = std::move(result.article_title); + suggestion->url = result.article_url.spec(); + suggestion->publisher_name = std::move(result.article_attribution); + suggestion->image_url = result.thumbnail_url.spec(); + suggestion->favicon_url = result.favicon_url.spec(); + + suggestions.push_back(std::move(suggestion)); + } + + std::move(callback).Run(std::move(suggestions)); +}
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h index e422b8f..277fb4c 100644 --- a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h +++ b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h
@@ -5,7 +5,10 @@ #ifndef CHROME_BROWSER_UI_WEBUI_FEED_INTERNALS_FEED_INTERNALS_PAGE_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_FEED_INTERNALS_FEED_INTERNALS_PAGE_HANDLER_H_ +#include <vector> + #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/ui/webui/feed_internals/feed_internals.mojom.h" #include "mojo/public/cpp/bindings/binding.h" @@ -13,9 +16,14 @@ namespace feed { class FeedHostService; +class FeedOfflineHost; class FeedSchedulerHost; } // namespace feed +namespace offline_pages { +struct PrefetchSuggestion; +} // namespace offline_pages + // Concrete implementation of feed_internals::mojom::PageHandler. class FeedInternalsPageHandler : public feed_internals::mojom::PageHandler { public: @@ -31,15 +39,23 @@ void ClearUserClassifierProperties() override; void GetLastFetchProperties(GetLastFetchPropertiesCallback) override; void ClearCachedDataAndRefreshFeed() override; + void GetCurrentContent(GetCurrentContentCallback) override; private: // Binding from the mojo interface to concrete implementation. mojo::Binding<feed_internals::mojom::PageHandler> binding_; + void OnGetCurrentArticleSuggestionsDone( + GetCurrentContentCallback callback, + std::vector<offline_pages::PrefetchSuggestion> suggestions); + // Services that provide the data and functionality. feed::FeedSchedulerHost* feed_scheduler_host_; + feed::FeedOfflineHost* feed_offline_host_; PrefService* pref_service_; + base::WeakPtrFactory<FeedInternalsPageHandler> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(FeedInternalsPageHandler); };
diff --git a/chrome/browser/ui/webui/managed_ui_handler.cc b/chrome/browser/ui/webui/managed_ui_handler.cc index 41dbfb2..4a69e87 100644 --- a/chrome/browser/ui/webui/managed_ui_handler.cc +++ b/chrome/browser/ui/webui/managed_ui_handler.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/bind.h" +#include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" @@ -14,7 +15,9 @@ #include "chrome/browser/policy/profile_policy_connector_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/managed_ui.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/web_ui.h" @@ -119,10 +122,16 @@ std::unique_ptr<base::DictionaryValue> ManagedUIHandler::GetDataSourceUpdate() const { auto update = std::make_unique<base::DictionaryValue>(); + + bool link_to_management_page = base::FeatureList::IsEnabled( + features::kLinkManagedNoticeToChromeUIManagementURL); + update->SetKey("managedByOrg", base::Value(l10n_util::GetStringFUTF16( IDS_MANAGED_BY_ORG_WITH_HYPERLINK, - base::UTF8ToUTF16(chrome::kChromeUIManagementURL) + base::UTF8ToUTF16(link_to_management_page + ? chrome::kChromeUIManagementURL + : chrome::kManagedUiLearnMoreUrl) #if defined(OS_CHROMEOS) , ui::GetChromeOSDeviceName()
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc index 1c4fe594..e96e1e9 100644 --- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc +++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
@@ -166,7 +166,8 @@ offline_page->SetDouble("creationTime", page.creation_time.ToJsTime()); offline_page->SetDouble("lastAccessTime", page.last_access_time.ToJsTime()); offline_page->SetInteger("accessCount", page.access_count); - offline_page->SetString("originalUrl", page.original_url.spec()); + offline_page->SetString("originalUrl", + page.original_url_if_different.spec()); offline_page->SetString("requestOrigin", page.request_origin); results.Append(std::move(offline_page)); }
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 424212a..5248587f 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -30,7 +30,6 @@ #include "chrome/browser/printing/print_preview_data_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_pages.h" -#include "chrome/browser/ui/webui/dark_mode_handler.h" #include "chrome/browser/ui/webui/localized_string.h" #include "chrome/browser/ui/webui/metrics_handler.h" #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h" @@ -472,7 +471,6 @@ // Set up the chrome://print/ data source. Profile* profile = Profile::FromWebUI(web_ui); content::WebUIDataSource* source = CreatePrintPreviewUISource(profile); - DarkModeHandler::Initialize(web_ui, source); content::WebUIDataSource::Add(profile, source); // Set up the chrome://theme/ source.
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index 291fbdf2..8120165 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -131,7 +131,7 @@ #include "chrome/browser/ui/webui/settings/printing_handler.h" #endif -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(SAFE_BROWSING_FULL) #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" #include "chrome/browser/ui/webui/settings/change_password_handler.h" #endif @@ -268,7 +268,7 @@ #endif // OS_WIN && defined(GOOGLE_CHROME_BUILD) bool password_protection_available = false; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(SAFE_BROWSING_FULL) safe_browsing::ChromePasswordProtectionService* password_protection = safe_browsing::ChromePasswordProtectionService:: GetPasswordProtectionService(profile);
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc index 71096cd9..fd96a72 100644 --- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc +++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc
@@ -121,19 +121,15 @@ } std::unique_ptr<base::ListValue> ManageProfileHandler::GetAvailableIcons() { - std::unique_ptr<base::ListValue> avatars( - profiles::GetDefaultProfileAvatarIconsAndLabels()); - PrefService* pref_service = profile_->GetPrefs(); bool using_gaia = pref_service->GetBoolean(prefs::kProfileUsingGAIAAvatar); + size_t selected_avatar_idx = + using_gaia ? SIZE_MAX + : pref_service->GetInteger(prefs::kProfileAvatarIndex); - // Select the avatar from the default set. - if (!using_gaia) { - size_t index = pref_service->GetInteger(prefs::kProfileAvatarIndex); - base::DictionaryValue* avatar = nullptr; - if (avatars->GetDictionary(index, &avatar)) - avatar->SetBoolean("selected", true); - } + // Obtain a list of the default avatar icons. + std::unique_ptr<base::ListValue> avatars( + profiles::GetDefaultProfileAvatarIconsAndLabels(selected_avatar_idx)); // Add the GAIA picture to the beginning of the list if it is available. ProfileAttributesEntry* entry;
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h index 659ef79..32da11d3 100644 --- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h +++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
@@ -44,6 +44,8 @@ FRIEND_TEST_ALL_PREFIXES(ManageProfileHandlerTest, HandleSetProfileName); FRIEND_TEST_ALL_PREFIXES(ManageProfileHandlerTest, HandleGetAvailableIcons); FRIEND_TEST_ALL_PREFIXES(ManageProfileHandlerTest, + HandleGetAvailableIconsOldIconSelected); + FRIEND_TEST_ALL_PREFIXES(ManageProfileHandlerTest, HandleGetAvailableIconsGaiaAvatarSelected); // Callback for the "getAvailableIcons" message.
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler_unittest.cc b/chrome/browser/ui/webui/settings/settings_manage_profile_handler_unittest.cc index d981468..d7ee5c1 100644 --- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" @@ -79,8 +80,10 @@ const base::DictionaryValue* icon = nullptr; EXPECT_TRUE(icons->GetDictionary(i, &icon)); std::string icon_url; + size_t icon_index; EXPECT_TRUE(icon->GetString("url", &icon_url)); EXPECT_FALSE(icon_url.empty()); + EXPECT_TRUE(profiles::IsDefaultAvatarIconUrl(icon_url, &icon_index)); std::string icon_label; EXPECT_TRUE(icon->GetString("label", &icon_label)); EXPECT_FALSE(icon_label.empty()); @@ -88,7 +91,7 @@ bool has_icon_selected = icon->GetBoolean("selected", &icon_selected); if (all_not_selected) { EXPECT_FALSE(has_icon_selected); - } else if (selected_index == i) { + } else if (selected_index == icon_index) { EXPECT_TRUE(has_icon_selected); EXPECT_TRUE(icon_selected); } @@ -126,7 +129,7 @@ TEST_F(ManageProfileHandlerTest, HandleGetAvailableIcons) { PrefService* pref_service = profile()->GetPrefs(); - pref_service->SetInteger(prefs::kProfileAvatarIndex, 7); + pref_service->SetInteger(prefs::kProfileAvatarIndex, 27); base::ListValue list_args_1; list_args_1.AppendString("get-icons-callback-id"); @@ -141,12 +144,32 @@ ASSERT_TRUE(data_1.arg1()->GetAsString(&callback_id_1)); EXPECT_EQ("get-icons-callback-id", callback_id_1); - VerifyIconListWithSingleSelection(data_1.arg3(), 7); + VerifyIconListWithSingleSelection(data_1.arg3(), 27); +} + +TEST_F(ManageProfileHandlerTest, HandleGetAvailableIconsOldIconSelected) { + PrefService* pref_service = profile()->GetPrefs(); + pref_service->SetInteger(prefs::kProfileAvatarIndex, 7); + + base::ListValue list_args; + list_args.AppendString("get-icons-callback-id"); + handler()->HandleGetAvailableIcons(&list_args); + + EXPECT_EQ(1U, web_ui()->call_data().size()); + + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIResponse", data.function_name()); + + std::string callback_id; + ASSERT_TRUE(data.arg1()->GetAsString(&callback_id)); + EXPECT_EQ("get-icons-callback-id", callback_id); + + VerifyIconListWithNoneSelected(data.arg3()); } TEST_F(ManageProfileHandlerTest, HandleGetAvailableIconsGaiaAvatarSelected) { PrefService* pref_service = profile()->GetPrefs(); - pref_service->SetInteger(prefs::kProfileAvatarIndex, 7); + pref_service->SetInteger(prefs::kProfileAvatarIndex, 27); pref_service->SetBoolean(prefs::kProfileUsingGAIAAvatar, true); base::ListValue list_args;
diff --git a/chrome/browser/ui/webui/signin/md_user_manager_ui.cc b/chrome/browser/ui/webui/signin/md_user_manager_ui.cc index 7c65f834..c012745 100644 --- a/chrome/browser/ui/webui/signin/md_user_manager_ui.cc +++ b/chrome/browser/ui/webui/signin/md_user_manager_ui.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_shortcut_manager.h" #include "chrome/browser/signin/signin_util.h" -#include "chrome/browser/ui/webui/dark_mode_handler.h" #include "chrome/browser/ui/webui/signin/signin_create_profile_handler.h" #include "chrome/browser/ui/webui/signin/signin_utils.h" #include "chrome/browser/ui/webui/signin/user_manager_screen_handler.h" @@ -45,7 +44,6 @@ // Set up the chrome://md-user-manager/ source. auto* md_user_source = CreateUIDataSource(localized_strings); - DarkModeHandler::Initialize(web_ui, md_user_source); content::WebUIDataSource::Add(profile, md_user_source); // Set up the chrome://theme/ source
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc index 2bfcee6c..91ffa695 100644 --- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc +++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -107,8 +107,8 @@ // it will be pixelated when displayed in the User Manager, so we should // return the placeholder avatar instead. gfx::Image avatar_image = entry->GetAvatarIcon(); - if (avatar_image.Width() <= profiles::kAvatarIconWidth || - avatar_image.Height() <= profiles::kAvatarIconHeight ) { + if (avatar_image.Width() <= profiles::kAvatarIconSize || + avatar_image.Height() <= profiles::kAvatarIconSize) { avatar_image = ui::ResourceBundle::GetSharedInstance().GetImageNamed( profiles::GetPlaceholderAvatarIconResourceID()); } @@ -631,8 +631,6 @@ localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); localized_strings->SetString( "browseAsGuest", l10n_util::GetStringUTF16(IDS_BROWSE_AS_GUEST_BUTTON)); - localized_strings->SetString("signOutUser", - l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT)); localized_strings->SetString("addSupervisedUser", l10n_util::GetStringUTF16(IDS_CREATE_LEGACY_SUPERVISED_USER_MENU_LABEL)); @@ -733,7 +731,6 @@ localized_strings->SetString("publicSessionSelectLanguage", ""); localized_strings->SetString("publicSessionSelectKeyboard", ""); localized_strings->SetString("signinBannerText", ""); - localized_strings->SetString("launchAppButton", ""); localized_strings->SetString("multiProfilesRestrictedPolicyTitle", ""); localized_strings->SetString("multiProfilesNotAllowedPolicyMsg", ""); localized_strings->SetString("multiProfilesPrimaryOnlyPolicyMsg", "");
diff --git a/chrome/browser/ui/webui/usb_internals/BUILD.gn b/chrome/browser/ui/webui/usb_internals/BUILD.gn index 7c2e8a4..958fa821 100644 --- a/chrome/browser/ui/webui/usb_internals/BUILD.gn +++ b/chrome/browser/ui/webui/usb_internals/BUILD.gn
@@ -10,6 +10,7 @@ ] deps = [ + "//device/usb/public/mojom:mojom", "//device/usb/public/mojom:test", ] }
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals.mojom b/chrome/browser/ui/webui/usb_internals/usb_internals.mojom index fede6b0..4066228 100644 --- a/chrome/browser/ui/webui/usb_internals/usb_internals.mojom +++ b/chrome/browser/ui/webui/usb_internals/usb_internals.mojom
@@ -4,9 +4,13 @@ module mojom; +import "device/usb/public/mojom/device_manager.mojom"; import "device/usb/public/mojom/device_manager_test.mojom"; interface UsbInternalsPageHandler { + // Bind the UsbDeviceManager interface to get all devices that connected. + BindUsbDeviceManagerInterface(device.mojom.UsbDeviceManager& request); + // Simulate the connection of a new device with the given properties. BindTestInterface(device.mojom.UsbDeviceManagerTest& request); };
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc index 881d85b..3775ba9c 100644 --- a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc
@@ -23,3 +23,11 @@ ->GetConnector() ->BindInterface(device::mojom::kServiceName, std::move(request)); } + +void UsbInternalsPageHandler::BindUsbDeviceManagerInterface( + device::mojom::UsbDeviceManagerRequest request) { + // Forward the request to the DeviceService. + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindInterface(device::mojom::kServiceName, std::move(request)); +}
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h index cd32dd4..b340c46c 100644 --- a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "chrome/browser/ui/webui/usb_internals/usb_internals.mojom.h" +#include "device/usb/public/mojom/device_manager.mojom.h" #include "device/usb/public/mojom/device_manager_test.mojom.h" #include "mojo/public/cpp/bindings/binding.h" @@ -16,7 +17,9 @@ mojom::UsbInternalsPageHandlerRequest request); ~UsbInternalsPageHandler() override; - // mojom::UsbInternalsPageHandler overrides: + void BindUsbDeviceManagerInterface( + device::mojom::UsbDeviceManagerRequest request) override; + void BindTestInterface( device::mojom::UsbDeviceManagerTestRequest request) override;
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc index 79e98188..efc72f6 100644 --- a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc
@@ -16,15 +16,23 @@ // Set up the chrome://usb-internals source. content::WebUIDataSource* source = content::WebUIDataSource::Create(chrome::kChromeUIUsbInternalsHost); + source->AddResourcePath("usb_internals.css", IDR_USB_INTERNALS_CSS); source->AddResourcePath("usb_internals.js", IDR_USB_INTERNALS_JS); - source->AddResourcePath( - "device/usb/public/mojom/device_manager_test.mojom-lite.js", - IDR_USB_DEVICE_MANAGER_TEST_MOJO_JS); - source->AddResourcePath( - "chrome/browser/ui/webui/usb_internals/usb_internals.mojom-lite.js", - IDR_USB_INTERNALS_MOJO_JS); - source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS); + source->AddResourcePath("usb_internals.mojom-lite.js", + IDR_USB_INTERNALS_MOJOM_LITE_JS); + source->AddResourcePath("devices_page.js", IDR_USB_INTERNALS_DEVICES_PAGE_JS); + source->AddResourcePath("device.mojom-lite.js", IDR_USB_DEVICE_MOJOM_LITE_JS); + source->AddResourcePath("device_enumeration_options.mojom-lite.js", + IDR_USB_DEVICE_ENUMERATION_OPTIONS_MOJOM_LITE_JS); + source->AddResourcePath("device_manager.mojom-lite.js", + IDR_USB_DEVICE_MANAGER_MOJOM_LITE_JS); + source->AddResourcePath("device_manager_client.mojom-lite.js", + IDR_USB_DEVICE_MANAGER_CLIENT_MOJOM_LITE_JS); + source->AddResourcePath("device_manager_test.mojom-lite.js", + IDR_USB_DEVICE_MANAGER_TEST_MOJOM_LITE_JS); + source->AddResourcePath("url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS); + source->SetDefaultResource(IDR_USB_INTERNALS_HTML); source->UseGzip();
diff --git a/chrome/browser/vr/service/xr_runtime_manager.cc b/chrome/browser/vr/service/xr_runtime_manager.cc index 86bdc18..a7c69ba 100644 --- a/chrome/browser/vr/service/xr_runtime_manager.cc +++ b/chrome/browser/vr/service/xr_runtime_manager.cc
@@ -190,8 +190,9 @@ return orientation_runtime; } - // Otherwise fall back to immersive providers. - return GetImmersiveRuntime(); + // If we don't have an orientation provider, then we don't have an explicit + // runtime to back a non-immersive session + return nullptr; } }
diff --git a/chrome/browser/web_applications/components/install_finalizer.h b/chrome/browser/web_applications/components/install_finalizer.h index c02209f82..3b47642 100644 --- a/chrome/browser/web_applications/components/install_finalizer.h +++ b/chrome/browser/web_applications/components/install_finalizer.h
@@ -41,7 +41,8 @@ virtual bool CanPinAppToShelf() const = 0; virtual void PinAppToShelf(const AppId& app_id) = 0; - virtual bool CanReparentTab(bool shortcut_created) const = 0; + virtual bool CanReparentTab(const AppId& app_id, + bool shortcut_created) const = 0; virtual void ReparentTab(const AppId& app_id, content::WebContents* web_contents) = 0;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc index 62210fc..a2fc2a72 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -116,8 +116,10 @@ BookmarkAppPinToShelf(app); } -bool BookmarkAppInstallFinalizer::CanReparentTab(bool shortcut_created) const { - return CanBookmarkAppReparentTab(shortcut_created); +bool BookmarkAppInstallFinalizer::CanReparentTab(const web_app::AppId& app_id, + bool shortcut_created) const { + const Extension* app = GetExtensionById(profile_, app_id); + return CanBookmarkAppReparentTab(profile_, app, shortcut_created); } void BookmarkAppInstallFinalizer::ReparentTab(
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h index 9a6ea48..9e5ad545 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h +++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h
@@ -33,7 +33,8 @@ CreateOsShortcutsCallback callback) override; bool CanPinAppToShelf() const override; void PinAppToShelf(const web_app::AppId& app_id) override; - bool CanReparentTab(bool shortcut_created) const override; + bool CanReparentTab(const web_app::AppId& app_id, + bool shortcut_created) const override; void ReparentTab(const web_app::AppId& app_id, content::WebContents* web_contents) override; bool CanRevealAppShim() const override;
diff --git a/chrome/browser/web_applications/test/test_install_finalizer.cc b/chrome/browser/web_applications/test/test_install_finalizer.cc index eedfa1f2..bbe6ea1 100644 --- a/chrome/browser/web_applications/test/test_install_finalizer.cc +++ b/chrome/browser/web_applications/test/test_install_finalizer.cc
@@ -61,7 +61,8 @@ ++num_pin_app_to_shelf_calls_; } -bool TestInstallFinalizer::CanReparentTab(bool shortcut_created) const { +bool TestInstallFinalizer::CanReparentTab(const AppId& app_id, + bool shortcut_created) const { return true; }
diff --git a/chrome/browser/web_applications/test/test_install_finalizer.h b/chrome/browser/web_applications/test/test_install_finalizer.h index 7725c92..381c77d 100644 --- a/chrome/browser/web_applications/test/test_install_finalizer.h +++ b/chrome/browser/web_applications/test/test_install_finalizer.h
@@ -28,7 +28,8 @@ CreateOsShortcutsCallback callback) override; bool CanPinAppToShelf() const override; void PinAppToShelf(const AppId& app_id) override; - bool CanReparentTab(bool shortcut_created) const override; + bool CanReparentTab(const AppId& app_id, + bool shortcut_created) const override; void ReparentTab(const AppId& app_id, content::WebContents* web_contents) override; bool CanRevealAppShim() const override;
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index 93bd380..f4db22c 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -123,7 +123,8 @@ NOTIMPLEMENTED(); } -bool WebAppInstallFinalizer::CanReparentTab(bool shortcut_created) const { +bool WebAppInstallFinalizer::CanReparentTab(const AppId& app_id, + bool shortcut_created) const { // TODO(loyso): Implement it. NOTIMPLEMENTED(); return true;
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h index 12ec5c8..661fa127 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.h +++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -33,7 +33,8 @@ CreateOsShortcutsCallback callback) override; bool CanPinAppToShelf() const override; void PinAppToShelf(const AppId& app_id) override; - bool CanReparentTab(bool shortcut_created) const override; + bool CanReparentTab(const AppId& app_id, + bool shortcut_created) const override; void ReparentTab(const AppId& app_id, content::WebContents* web_contents) override; bool CanRevealAppShim() const override;
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc index 023640c8..c809e59 100644 --- a/chrome/browser/web_applications/web_app_install_manager.cc +++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -245,7 +245,7 @@ // TODO(loyso): Implement |reparent_tab| to skip tab reparenting logic. if (web_app_info->open_as_window && - install_finalizer_->CanReparentTab(shortcut_created)) { + install_finalizer_->CanReparentTab(app_id, shortcut_created)) { install_finalizer_->ReparentTab(app_id, web_contents()); }
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 184cc0e4..23585e76 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -248,7 +248,7 @@ #if defined(OS_CHROMEOS) // Enables event-based status reporting for child accounts in Chrome OS. const base::Feature kEventBasedStatusReporting{ - "EventBasedStatusReporting", base::FEATURE_DISABLED_BY_DEFAULT}; + "EventBasedStatusReporting", base::FEATURE_ENABLED_BY_DEFAULT}; #endif // An experimental way of showing app banners, which has modal banners and gives @@ -523,6 +523,10 @@ #if !defined(OS_ANDROID) const base::Feature kShowManagedUi{"ShowManagedUi", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kLinkManagedNoticeToChromeUIManagementURL{ + "LinkManagedNoticeToChromeUIManagementURL", + base::FEATURE_DISABLED_BY_DEFAULT}; #endif #if defined(OS_ANDROID) @@ -534,6 +538,9 @@ // Launch bug: https://crbug.com/810843. This is a //chrome-layer feature to // avoid turning on site-per-process by default for *all* //content embedders // (e.g. this approach lets ChromeCast avoid site-per-process mode). +// +// TODO(alexmos): Move this and the other site isolation features below to +// browser_features, as they are only used on the browser side. const base::Feature kSitePerProcess { "site-per-process", #if defined(OS_ANDROID) @@ -543,6 +550,15 @@ #endif }; +// Controls a mode for dynamically process-isolating sites where the user has +// entered a password. This is intended to be used primarily when full site +// isolation is turned off. To check whether this mode is enabled, use +// ChromeSiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() rather than +// checking the feature directly, since that decision is influenced by other +// factors as well. +const base::Feature kSiteIsolationForPasswordSites{ + "site-isolation-for-password-sites", base::FEATURE_DISABLED_BY_DEFAULT}; + // kSitePerProcessOnlyForHighMemoryClients is checked before kSitePerProcess, // and (if enabled) can restrict if kSitePerProcess feature is checked at all - // no check will be made on devices with low memory (these devices will have no
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index b773f3d..07dbaefed 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -352,6 +352,8 @@ #if !defined(OS_ANDROID) COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kShowManagedUi; +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kLinkManagedNoticeToChromeUIManagementURL; #endif #if defined(OS_ANDROID) @@ -364,6 +366,9 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSitePerProcess; COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kSiteIsolationForPasswordSites; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSitePerProcessOnlyForHighMemoryClients; COMPONENT_EXPORT(CHROME_FEATURES) extern const char kSitePerProcessOnlyForHighMemoryClientsParamName[];
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 1a48c37..c4f4376 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -153,9 +153,8 @@ const char kLegacySupervisedUserManagementURL[] = "https://www.chrome.com/manage"; -// TODO(nicolaso): Replace with a p-link once it's ready. b/117655761 const char kManagedUiLearnMoreUrl[] = - "https://support.google.com/chromebook/answer/1331549"; + "https://support.google.com/chromebook/?p=is_chrome_managed"; const char kMyActivityUrlInClearBrowsingData[] = "https://myactivity.google.com/myactivity/?utm_source=chrome_cbd";
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc index d49bc00..fc4215a0 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
@@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" +#include "base/win/windows_version.h" #include "chrome/common/chrome_version.h" #include "chrome/credential_provider/eventlog/gcp_eventlog_messages.h" #include "chrome/credential_provider/gaiacp/associated_user_validator.h" @@ -116,7 +117,9 @@ credential_provider::ConfigureGcpCrashReporting(*cmd_line); } - LOGFN(INFO) << "DllMain(DLL_PROCESS_ATTACH)"; + LOGFN(INFO) << "DllMain(DLL_PROCESS_ATTACH) Build: " + << base::win::OSInfo::GetInstance()->Kernel32BaseVersion() + << " Version:" << GetWindowsVersion(); break; } case DLL_PROCESS_DETACH:
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.cc b/chrome/credential_provider/gaiacp/gcp_utils.cc index c9cd131b..09adfcd 100644 --- a/chrome/credential_provider/gaiacp/gcp_utils.cc +++ b/chrome/credential_provider/gaiacp/gcp_utils.cc
@@ -246,7 +246,7 @@ } // Waits for a process to terminate while capturing output from |output_handle| -// to the buffer |output_buffer| of size |buffer_size|. The buffer is expected +// to the buffer |output_buffer| of length |buffer_size|. The buffer is expected // to be relatively small. The exit code of the process is written to // |exit_code|. HRESULT WaitForProcess(base::win::ScopedHandle::Handle process_handle, @@ -699,6 +699,18 @@ #endif } +base::string16 GetWindowsVersion() { + wchar_t release_id[32]; + ULONG length = base::size(release_id) * sizeof(release_id[0]); + HRESULT hr = + GetMachineRegString(L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + L"ReleaseId", release_id, &length); + if (SUCCEEDED(hr)) + return release_id; + + return L"Unknown"; +} + FakesForTesting::FakesForTesting() {} FakesForTesting::~FakesForTesting() {}
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.h b/chrome/credential_provider/gaiacp/gcp_utils.h index ded5915..4d36a18 100644 --- a/chrome/credential_provider/gaiacp/gcp_utils.h +++ b/chrome/credential_provider/gaiacp/gcp_utils.h
@@ -239,6 +239,11 @@ const std::unique_ptr<base::DictionaryValue>& dict, const char* name); +// Returns the major build version of Windows by reading the registry. +// See: +// https://stackoverflow.com/questions/31072543/reliable-way-to-get-windows-version-from-registry +base::string16 GetWindowsVersion(); + class OSUserManager; class OSProcessManager;
diff --git a/chrome/credential_provider/setup/setup.cc b/chrome/credential_provider/setup/setup.cc index 3babc53c..7560e73 100644 --- a/chrome/credential_provider/setup/setup.cc +++ b/chrome/credential_provider/setup/setup.cc
@@ -133,8 +133,10 @@ LOGFN(INFO) << "Module: " << gcp_setup_exe_path; LOGFN(INFO) << "Args: " << lpCmdLine; LOGFN(INFO) << "Version: " << TEXT(CHROME_VERSION_STRING); + LOGFN(INFO) << "Windows: " - << base::win::OSInfo::GetInstance()->Kernel32BaseVersion(); + << base::win::OSInfo::GetInstance()->Kernel32BaseVersion() + << " Version:" << credential_provider::GetWindowsVersion(); // If running from omaha, make sure machine install is used. if (IsPerUserInstallFromGoogleUpdate()) {
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index e86e1f0..245a7102 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -102,8 +102,8 @@ "sandbox_status_extension_android.h", "security_filter_peer.cc", "security_filter_peer.h", - "ssl/ssl_certificate_error_page_controller.cc", - "ssl/ssl_certificate_error_page_controller.h", + "security_interstitials/security_interstitial_page_controller.cc", + "security_interstitials/security_interstitial_page_controller.h", "supervised_user/supervised_user_error_page_controller.cc", "supervised_user/supervised_user_error_page_controller.h", "tts_dispatcher.cc",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index d007c01..27f4cff3 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -523,7 +523,7 @@ new nacl::NaClHelper(render_frame); #endif -#if defined(FULL_SAFE_BROWSING) || defined(SAFE_BROWSING_DB_REMOTE) +#if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE) safe_browsing::ThreatDOMDetails::Create(render_frame, registry); #endif
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc index 0081b5b..2eb6a965 100644 --- a/chrome/renderer/net/net_error_helper.cc +++ b/chrome/renderer/net/net_error_helper.cc
@@ -24,7 +24,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/chrome_render_thread_observer.h" -#include "chrome/renderer/ssl/ssl_certificate_error_page_controller.h" +#include "chrome/renderer/security_interstitials/security_interstitial_page_controller.h" #include "chrome/renderer/supervised_user/supervised_user_error_page_controller.h" #include "components/error_page/common/error.h" #include "components/error_page/common/error_page_params.h" @@ -167,7 +167,7 @@ : RenderFrameObserver(render_frame), content::RenderFrameObserverTracker<NetErrorHelper>(render_frame), weak_controller_delegate_factory_(this), - weak_ssl_error_controller_delegate_factory_(this), + weak_security_interstitial_controller_delegate_factory_(this), weak_supervised_user_error_controller_delegate_factory_(this) { RenderThread::Get()->AddObserver(this); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); @@ -324,7 +324,7 @@ // error page, the controller has not yet been attached, so this won't affect // it. weak_controller_delegate_factory_.InvalidateWeakPtrs(); - weak_ssl_error_controller_delegate_factory_.InvalidateWeakPtrs(); + weak_security_interstitial_controller_delegate_factory_.InvalidateWeakPtrs(); weak_supervised_user_error_controller_delegate_factory_.InvalidateWeakPtrs(); core_->OnCommitLoad(GetFrameType(render_frame()), @@ -433,9 +433,10 @@ failed_url, true /* replace_current_item */); } -void NetErrorHelper::EnablePageHelperFunctions(net::Error net_error) { - SSLCertificateErrorPageController::Install( - render_frame(), weak_ssl_error_controller_delegate_factory_.GetWeakPtr()); +void NetErrorHelper::EnablePageHelperFunctions() { + SecurityInterstitialPageController::Install( + render_frame(), + weak_security_interstitial_controller_delegate_factory_.GetWeakPtr()); NetErrorPageController::Install( render_frame(), weak_controller_delegate_factory_.GetWeakPtr());
diff --git a/chrome/renderer/net/net_error_helper.h b/chrome/renderer/net/net_error_helper.h index cf104cf8..0b259ec 100644 --- a/chrome/renderer/net/net_error_helper.h +++ b/chrome/renderer/net/net_error_helper.h
@@ -18,7 +18,7 @@ #include "chrome/common/supervised_user_commands.mojom.h" #include "chrome/renderer/net/net_error_helper_core.h" #include "chrome/renderer/net/net_error_page_controller.h" -#include "chrome/renderer/ssl/ssl_certificate_error_page_controller.h" +#include "chrome/renderer/security_interstitials/security_interstitial_page_controller.h" #include "chrome/renderer/supervised_user/supervised_user_error_page_controller.h" #include "chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate.h" #include "components/error_page/common/net_error_info.h" @@ -55,7 +55,7 @@ public content::RenderThreadObserver, public NetErrorHelperCore::Delegate, public NetErrorPageController::Delegate, - public SSLCertificateErrorPageController::Delegate, + public SecurityInterstitialPageController::Delegate, public SupervisedUserErrorPageControllerDelegate, public chrome::mojom::NetworkDiagnosticsClient, public chrome::mojom::NavigationCorrector { @@ -75,7 +75,7 @@ void UpdateEasterEggHighScore(int high_score) override; void ResetEasterEggHighScore() override; - // SSLCertificateErrorPageController::Delegate implementation + // SecurityInterstitialPageController::Delegate implementation void SendCommand( security_interstitials::SecurityInterstitialCommand command) override; @@ -130,7 +130,7 @@ bool* auto_fetch_allowed, std::string* html) const override; void LoadErrorPage(const std::string& html, const GURL& failed_url) override; - void EnablePageHelperFunctions(net::Error net_error) override; + void EnablePageHelperFunctions() override; void UpdateErrorPage(const error_page::Error& error, bool is_failed_post, bool can_use_local_diagnostics_service) override; @@ -207,8 +207,8 @@ base::WeakPtrFactory<NetErrorPageController::Delegate> weak_controller_delegate_factory_; - base::WeakPtrFactory<SSLCertificateErrorPageController::Delegate> - weak_ssl_error_controller_delegate_factory_; + base::WeakPtrFactory<SecurityInterstitialPageController::Delegate> + weak_security_interstitial_controller_delegate_factory_; base::WeakPtrFactory<SupervisedUserErrorPageControllerDelegate> weak_supervised_user_error_controller_delegate_factory_;
diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc index 721c1a2..3614c37c 100644 --- a/chrome/renderer/net/net_error_helper_core.cc +++ b/chrome/renderer/net/net_error_helper_core.cc
@@ -680,8 +680,7 @@ delegate_->SetIsShowingDownloadButton( committed_error_page_info_->download_button_in_page); - delegate_->EnablePageHelperFunctions( - static_cast<net::Error>(committed_error_page_info_->error.reason())); + delegate_->EnablePageHelperFunctions(); #if defined(OS_ANDROID) if (committed_error_page_info_->offline_content_feature_state ==
diff --git a/chrome/renderer/net/net_error_helper_core.h b/chrome/renderer/net/net_error_helper_core.h index 14ebf9c..2720c244 100644 --- a/chrome/renderer/net/net_error_helper_core.h +++ b/chrome/renderer/net/net_error_helper_core.h
@@ -80,7 +80,7 @@ // Create extra Javascript bindings in the error page. Will only be invoked // after an error page has finished loading. - virtual void EnablePageHelperFunctions(net::Error net_error) = 0; + virtual void EnablePageHelperFunctions() = 0; // Updates the currently displayed error page with a new error code. The // currently displayed error page must have finished loading, and must have
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc index 86a8b86..6847390d 100644 --- a/chrome/renderer/net/net_error_helper_core_unittest.cc +++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -390,7 +390,7 @@ last_error_html_ = html; } - void EnablePageHelperFunctions(net::Error net_error) override { + void EnablePageHelperFunctions() override { enable_page_helper_functions_count_++; }
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js index ecfe017..5399e46 100644 --- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -280,7 +280,7 @@ dispatch(args); }); -registerArgumentMassager('fileManagerPrivate.onCrostiniSharedPathsChanged', +registerArgumentMassager('fileManagerPrivate.onCrostiniChanged', function(args, dispatch) { // Convert entries arguments into real Entry objects. const entries = args[0].entries;
diff --git a/chrome/renderer/ssl/DEPS b/chrome/renderer/security_interstitials/DEPS similarity index 100% rename from chrome/renderer/ssl/DEPS rename to chrome/renderer/security_interstitials/DEPS
diff --git a/chrome/renderer/ssl/OWNERS b/chrome/renderer/security_interstitials/OWNERS similarity index 100% rename from chrome/renderer/ssl/OWNERS rename to chrome/renderer/security_interstitials/OWNERS
diff --git a/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc b/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc new file mode 100644 index 0000000..126e46c --- /dev/null +++ b/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc
@@ -0,0 +1,146 @@ +// Copyright 2018 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/renderer/security_interstitials/security_interstitial_page_controller.h" + +#include "components/security_interstitials/core/controller_client.h" +#include "content/public/renderer/render_frame.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "third_party/blink/public/web/blink.h" +#include "third_party/blink/public/web/web_local_frame.h" + +gin::WrapperInfo SecurityInterstitialPageController::kWrapperInfo = { + gin::kEmbedderNativeGin}; + +SecurityInterstitialPageController::Delegate::~Delegate() {} + +void SecurityInterstitialPageController::Install( + content::RenderFrame* render_frame, + base::WeakPtr<Delegate> delegate) { + v8::Isolate* isolate = blink::MainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = + render_frame->GetWebFrame()->MainWorldScriptContext(); + if (context.IsEmpty()) + return; + + v8::Context::Scope context_scope(context); + + gin::Handle<SecurityInterstitialPageController> controller = + gin::CreateHandle(isolate, + new SecurityInterstitialPageController(delegate)); + if (controller.IsEmpty()) + return; + + v8::Local<v8::Object> global = context->Global(); + global->Set(gin::StringToV8(isolate, "certificateErrorPageController"), + controller.ToV8()); +} + +SecurityInterstitialPageController::SecurityInterstitialPageController( + base::WeakPtr<Delegate> delegate) + : delegate_(delegate) {} + +SecurityInterstitialPageController::~SecurityInterstitialPageController() {} + +void SecurityInterstitialPageController::DontProceed() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_DONT_PROCEED); +} + +void SecurityInterstitialPageController::Proceed() { + SendCommand(security_interstitials::SecurityInterstitialCommand::CMD_PROCEED); +} + +void SecurityInterstitialPageController::ShowMoreSection() { + SendCommand(security_interstitials::SecurityInterstitialCommand:: + CMD_SHOW_MORE_SECTION); +} + +void SecurityInterstitialPageController::OpenHelpCenter() { + SendCommand(security_interstitials::SecurityInterstitialCommand:: + CMD_OPEN_HELP_CENTER); +} + +void SecurityInterstitialPageController::OpenDiagnostic() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_OPEN_DIAGNOSTIC); +} + +void SecurityInterstitialPageController::Reload() { + SendCommand(security_interstitials::SecurityInterstitialCommand::CMD_RELOAD); +} + +void SecurityInterstitialPageController::OpenDateSettings() { + SendCommand(security_interstitials::SecurityInterstitialCommand:: + CMD_OPEN_DATE_SETTINGS); +} + +void SecurityInterstitialPageController::OpenLogin() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_OPEN_LOGIN); +} + +void SecurityInterstitialPageController::DoReport() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_DO_REPORT); +} + +void SecurityInterstitialPageController::DontReport() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_DONT_REPORT); +} + +void SecurityInterstitialPageController::OpenReportingPrivacy() { + SendCommand(security_interstitials::SecurityInterstitialCommand:: + CMD_OPEN_REPORTING_PRIVACY); +} + +void SecurityInterstitialPageController::OpenWhitepaper() { + SendCommand( + security_interstitials::SecurityInterstitialCommand::CMD_OPEN_WHITEPAPER); +} + +void SecurityInterstitialPageController::ReportPhishingError() { + SendCommand(security_interstitials::SecurityInterstitialCommand:: + CMD_REPORT_PHISHING_ERROR); +} + +void SecurityInterstitialPageController::SendCommand( + security_interstitials::SecurityInterstitialCommand command) { + if (delegate_) { + delegate_->SendCommand(command); + } +} + +gin::ObjectTemplateBuilder +SecurityInterstitialPageController::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return gin::Wrappable<SecurityInterstitialPageController>:: + GetObjectTemplateBuilder(isolate) + .SetMethod("dontProceed", + &SecurityInterstitialPageController::DontProceed) + .SetMethod("proceed", &SecurityInterstitialPageController::Proceed) + .SetMethod("showMoreSection", + &SecurityInterstitialPageController::ShowMoreSection) + .SetMethod("openHelpCenter", + &SecurityInterstitialPageController::OpenHelpCenter) + .SetMethod("openDiagnostic", + &SecurityInterstitialPageController::OpenDiagnostic) + .SetMethod("reload", &SecurityInterstitialPageController::Reload) + .SetMethod("openDateSettings", + &SecurityInterstitialPageController::OpenDateSettings) + .SetMethod("openLogin", + &SecurityInterstitialPageController::OpenLogin) + .SetMethod("doReport", &SecurityInterstitialPageController::DoReport) + .SetMethod("dontReport", + &SecurityInterstitialPageController::DontReport) + .SetMethod("openReportingPrivacy", + &SecurityInterstitialPageController::OpenReportingPrivacy) + .SetMethod("openWhitepaper", + &SecurityInterstitialPageController::OpenWhitepaper) + .SetMethod("reportPhishingError", + &SecurityInterstitialPageController::ReportPhishingError); +}
diff --git a/chrome/renderer/ssl/ssl_certificate_error_page_controller.h b/chrome/renderer/security_interstitials/security_interstitial_page_controller.h similarity index 76% rename from chrome/renderer/ssl/ssl_certificate_error_page_controller.h rename to chrome/renderer/security_interstitials/security_interstitial_page_controller.h index b550222..967a9e7 100644 --- a/chrome/renderer/ssl/ssl_certificate_error_page_controller.h +++ b/chrome/renderer/security_interstitials/security_interstitial_page_controller.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 CHROME_RENDERER_SSL_SSL_CERTIFICATE_ERROR_PAGE_CONTROLLER_H_ -#define CHROME_RENDERER_SSL_SSL_CERTIFICATE_ERROR_PAGE_CONTROLLER_H_ +#ifndef CHROME_RENDERER_SECURITY_INTERSTITIALS_SECURITY_INTERSTITIAL_PAGE_CONTROLLER_H_ +#define CHROME_RENDERER_SECURITY_INTERSTITIALS_SECURITY_INTERSTITIAL_PAGE_CONTROLLER_H_ #include "base/memory/weak_ptr.h" #include "components/security_interstitials/core/controller_client.h" @@ -16,8 +16,8 @@ // This class makes various helper functions available to interstitials // when committed interstitials are on. It is bound to the JavaScript // window.certificateErrorPageController object. -class SSLCertificateErrorPageController - : public gin::Wrappable<SSLCertificateErrorPageController> { +class SecurityInterstitialPageController + : public gin::Wrappable<SecurityInterstitialPageController> { public: static gin::WrapperInfo kWrapperInfo; @@ -40,8 +40,8 @@ base::WeakPtr<Delegate> delegate); private: - explicit SSLCertificateErrorPageController(base::WeakPtr<Delegate> delegate); - ~SSLCertificateErrorPageController() override; + explicit SecurityInterstitialPageController(base::WeakPtr<Delegate> delegate); + ~SecurityInterstitialPageController() override; void DontProceed(); void Proceed(); @@ -65,7 +65,7 @@ base::WeakPtr<Delegate> const delegate_; - DISALLOW_COPY_AND_ASSIGN(SSLCertificateErrorPageController); + DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialPageController); }; -#endif // CHROME_RENDERER_SSL_SSL_CERTIFICATE_ERROR_PAGE_CONTROLLER_H_ +#endif // CHROME_RENDERER_SECURITY_INTERSTITIALS_SECURITY_INTERSTITIAL_PAGE_CONTROLLER_H_
diff --git a/chrome/renderer/ssl/ssl_certificate_error_page_controller.cc b/chrome/renderer/ssl/ssl_certificate_error_page_controller.cc deleted file mode 100644 index a5516d60..0000000 --- a/chrome/renderer/ssl/ssl_certificate_error_page_controller.cc +++ /dev/null
@@ -1,144 +0,0 @@ -// Copyright 2018 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/renderer/ssl/ssl_certificate_error_page_controller.h" - -#include "components/security_interstitials/core/controller_client.h" -#include "content/public/renderer/render_frame.h" -#include "gin/handle.h" -#include "gin/object_template_builder.h" -#include "third_party/blink/public/web/blink.h" -#include "third_party/blink/public/web/web_local_frame.h" - -gin::WrapperInfo SSLCertificateErrorPageController::kWrapperInfo = { - gin::kEmbedderNativeGin}; - -SSLCertificateErrorPageController::Delegate::~Delegate() {} - -void SSLCertificateErrorPageController::Install( - content::RenderFrame* render_frame, - base::WeakPtr<Delegate> delegate) { - v8::Isolate* isolate = blink::MainThreadIsolate(); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = - render_frame->GetWebFrame()->MainWorldScriptContext(); - if (context.IsEmpty()) - return; - - v8::Context::Scope context_scope(context); - - gin::Handle<SSLCertificateErrorPageController> controller = gin::CreateHandle( - isolate, new SSLCertificateErrorPageController(delegate)); - if (controller.IsEmpty()) - return; - - v8::Local<v8::Object> global = context->Global(); - global->Set(gin::StringToV8(isolate, "certificateErrorPageController"), - controller.ToV8()); -} - -SSLCertificateErrorPageController::SSLCertificateErrorPageController( - base::WeakPtr<Delegate> delegate) - : delegate_(delegate) {} - -SSLCertificateErrorPageController::~SSLCertificateErrorPageController() {} - -void SSLCertificateErrorPageController::DontProceed() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_DONT_PROCEED); -} - -void SSLCertificateErrorPageController::Proceed() { - SendCommand(security_interstitials::SecurityInterstitialCommand::CMD_PROCEED); -} - -void SSLCertificateErrorPageController::ShowMoreSection() { - SendCommand(security_interstitials::SecurityInterstitialCommand:: - CMD_SHOW_MORE_SECTION); -} - -void SSLCertificateErrorPageController::OpenHelpCenter() { - SendCommand(security_interstitials::SecurityInterstitialCommand:: - CMD_OPEN_HELP_CENTER); -} - -void SSLCertificateErrorPageController::OpenDiagnostic() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_OPEN_DIAGNOSTIC); -} - -void SSLCertificateErrorPageController::Reload() { - SendCommand(security_interstitials::SecurityInterstitialCommand::CMD_RELOAD); -} - -void SSLCertificateErrorPageController::OpenDateSettings() { - SendCommand(security_interstitials::SecurityInterstitialCommand:: - CMD_OPEN_DATE_SETTINGS); -} - -void SSLCertificateErrorPageController::OpenLogin() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_OPEN_LOGIN); -} - -void SSLCertificateErrorPageController::DoReport() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_DO_REPORT); -} - -void SSLCertificateErrorPageController::DontReport() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_DONT_REPORT); -} - -void SSLCertificateErrorPageController::OpenReportingPrivacy() { - SendCommand(security_interstitials::SecurityInterstitialCommand:: - CMD_OPEN_REPORTING_PRIVACY); -} - -void SSLCertificateErrorPageController::OpenWhitepaper() { - SendCommand( - security_interstitials::SecurityInterstitialCommand::CMD_OPEN_WHITEPAPER); -} - -void SSLCertificateErrorPageController::ReportPhishingError() { - SendCommand(security_interstitials::SecurityInterstitialCommand:: - CMD_REPORT_PHISHING_ERROR); -} - -void SSLCertificateErrorPageController::SendCommand( - security_interstitials::SecurityInterstitialCommand command) { - if (delegate_) { - delegate_->SendCommand(command); - } -} - -gin::ObjectTemplateBuilder -SSLCertificateErrorPageController::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return gin::Wrappable<SSLCertificateErrorPageController>:: - GetObjectTemplateBuilder(isolate) - .SetMethod("dontProceed", - &SSLCertificateErrorPageController::DontProceed) - .SetMethod("proceed", &SSLCertificateErrorPageController::Proceed) - .SetMethod("showMoreSection", - &SSLCertificateErrorPageController::ShowMoreSection) - .SetMethod("openHelpCenter", - &SSLCertificateErrorPageController::OpenHelpCenter) - .SetMethod("openDiagnostic", - &SSLCertificateErrorPageController::OpenDiagnostic) - .SetMethod("reload", &SSLCertificateErrorPageController::Reload) - .SetMethod("openDateSettings", - &SSLCertificateErrorPageController::OpenDateSettings) - .SetMethod("openLogin", &SSLCertificateErrorPageController::OpenLogin) - .SetMethod("doReport", &SSLCertificateErrorPageController::DoReport) - .SetMethod("dontReport", - &SSLCertificateErrorPageController::DontReport) - .SetMethod("openReportingPrivacy", - &SSLCertificateErrorPageController::OpenReportingPrivacy) - .SetMethod("openWhitepaper", - &SSLCertificateErrorPageController::OpenWhitepaper) - .SetMethod("reportPhishingError", - &SSLCertificateErrorPageController::ReportPhishingError); -}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 2c82510a..6450d4c 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -831,6 +831,7 @@ "../browser/previews/lazyload_browsertest.cc", "../browser/previews/previews_browsertest.cc", "../browser/previews/previews_lite_page_browsertest.cc", + "../browser/previews/previews_oneplatform_hints_browsertest.cc", "../browser/previews/previews_service_browser_test.cc", "../browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc", "../browser/process_singleton_browsertest.cc", @@ -1820,6 +1821,8 @@ "../browser/chromeos/login/lock/screen_locker_browsertest.cc", "../browser/chromeos/login/lock/screen_locker_tester.cc", "../browser/chromeos/login/lock/screen_locker_tester.h", + "../browser/chromeos/login/test/login_screen_tester.cc", + "../browser/chromeos/login/test/login_screen_tester.h", "../browser/chromeos/login/login_auth_recorder_browsertest.cc", "../browser/chromeos/login/login_browsertest.cc", "../browser/chromeos/login/login_manager_test.cc", @@ -3798,6 +3801,7 @@ "../browser/extensions/api/identity/identity_api_unittest.cc", "../browser/extensions/api/identity/identity_mint_queue_unittest.cc", "../browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc", + "../browser/extensions/api/image_writer_private/image_writer_private_api_unittest.cc", "../browser/extensions/api/image_writer_private/operation_manager_unittest.cc", "../browser/extensions/api/image_writer_private/operation_unittest.cc", "../browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc", @@ -4242,6 +4246,9 @@ "//components/safe_browsing/db:v4_test_util", "//components/safe_browsing/renderer:websocket_sb_handshake_throttle_unittest", ] + } else if (safe_browsing_mode == 2) { + sources += [ "../browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc" ] + deps += [] } if (enable_plugins) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java index 6ac22f0f..7d3ce88 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
@@ -18,7 +18,7 @@ import org.chromium.chrome.browser.suggestions.TileSource; import org.chromium.chrome.browser.suggestions.TileTitleSource; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.touchless.TouchlessNewTabPage; +import org.chromium.chrome.browser.touchless.TouchlessDelegate; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.test.util.AccountHolder; @@ -49,7 +49,7 @@ public boolean isSatisfied() { if (!tab.isIncognito()) { if (FeatureUtilities.isNoTouchModeEnabled()) { - return tab.getNativePage() instanceof TouchlessNewTabPage; + return TouchlessDelegate.isTouchlessNewTabPage(tab.getNativePage()); } // TODO(tedchoc): Make MostVisitedPage also have a isLoaded() concept. if (tab.getNativePage() instanceof NewTabPage) {
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index 0bad1a5..d6ac6e9 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -72,7 +72,7 @@ int reason) override {} void OnTabDetached(content::WebContents* contents, bool was_active) override { } - void OnTabRestoredFromMenu(int command_id) override {} + void OnTabRestored(int command_id) override {} void ZoomChangedForActiveTab(bool can_show_bubble) override {} gfx::Rect GetRestoredBounds() const override; ui::WindowShowState GetRestoredState() const override;
diff --git a/chrome/test/chromedriver/README.txt b/chrome/test/chromedriver/README.txt index eaddce6..bf02132 100644 --- a/chrome/test/chromedriver/README.txt +++ b/chrome/test/chromedriver/README.txt
@@ -1,8 +1,9 @@ This file contains high-level info about how ChromeDriver works and how to contribute. -ChromeDriver is an implementation of the WebDriver standard, -which allows users to automate testing of their website across browsers. +ChromeDriver is an implementation of the WebDriver standard +(https://w3c.github.io/webdriver/), which allows users to automate testing of +their website across browsers. See the user site at https://sites.google.com/a/chromium.org/chromedriver/ @@ -11,7 +12,10 @@ create an executable binary in the build folder named 'chromedriver[.exe]'. -Once built, ChromeDriver can be used interactively with python. +Once built, ChromeDriver can be used with various third-party libraries that +support WebDriver protocol, including language bindings provided by Selenium. + +For testing purposes, ChromeDriver can be used interactively with python. $ export PYTHONPATH=<THIS_DIR>/server:<THIS_DIR>/client $ python @@ -25,7 +29,7 @@ ChromeDriver will use the system installed Chrome by default. -To use ChromeDriver2 with Chrome on Android pass the Android package name in the +To use ChromeDriver with Chrome on Android pass the Android package name in the chromeOptions.androidPackage capability when creating the driver. The path to adb_commands.py and the adb tool from the Android SDK must be set in PATH. For more detailed instructions see the user site. @@ -79,30 +83,25 @@ Third party libraries used by chromedriver. =====Testing===== -See the ChromeDriver waterfall at: - http://build.chromium.org/p/chromium.chromedriver/waterfall -There are 4 test suites for verifying ChromeDriver's correctness: +There are several test suites for verifying ChromeDriver's correctness: -1) chromedriver_unittests (chrome/chrome_tests.gypi) -This is the unittest target, which runs on the main waterfall on win/mac/linux -and can close the tree. It is also run on the commit queue and try bots by -default. Tests should take a few milliseconds and be very stable. +* chromedriver_unittests +This is the unittest target, which runs on the commit queue on win/mac/linux. +Tests should take a few milliseconds and be very stable. -2) chromedriver_tests (chrome/chrome_tests.gypi) -This is a collection of C++ medium sized tests which can be run optionally -on the trybots. +* python integration tests (test/run_py_tests.py) +These tests are maintained by the ChromeDriver team, and are intended to verify +that ChromeDriver works correctly with Chrome. Run test/run_py_tests.py --help +for more info. These are run on the commit queue on win/mac/linux. -3) python integration tests -Run test/run_py_tests.py --help for more info. These are only run on the -ChromeDriver waterfall. - -4) WebDriver Java acceptance tests +* WebDriver Java acceptance tests (test/run_java_tests.py) These are integration tests from the WebDriver open source project which can -be run via test/run_java_tests.py. They are only run on the ChromeDriver -bots. Run with --help for more info. +be run via test/run_java_tests.py. They are not currently run on any bots, but +will be included in the commit queue in the future. Run with --help for more +info. =====Contributing===== Find an open issue and submit a patch for review by an individual listed in the OWNERS file in this directory. Issues are tracked in chromedriver's issue tracker: - https://code.google.com/p/chromedriver/issues/list + https://bugs.chromium.org/p/chromedriver/issues/list
diff --git a/chrome/test/chromedriver/archive.py b/chrome/test/chromedriver/archive.py deleted file mode 100644 index e35c7e2..0000000 --- a/chrome/test/chromedriver/archive.py +++ /dev/null
@@ -1,152 +0,0 @@ -# Copyright (c) 2013 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. - -"""Downloads items from the Chromium snapshot archive.""" - -import json -import os -import re -import urllib -import urllib2 - -import util - -_SITE = 'http://commondatastorage.googleapis.com' -GS_GIT_LOG_URL = ( - 'https://chromium.googlesource.com/chromium/src/+/%s?format=json') -GS_SEARCH_PATTERN = r'Cr-Commit-Position: refs/heads/master@{#(\d+)}' -CR_REV_URL = 'https://cr-rev.appspot.com/_ah/api/crrev/v1/redirect/%s' - - -class Site(object): - CHROMIUM_SNAPSHOT = _SITE + '/chromium-browser-snapshots' - - -def GetLatestRevision(): - """Returns the latest revision (as a string) available for this platform. - - Args: - site: the archive site to check against, default to the snapshot one. - """ - url = '%s/%s/LAST_CHANGE' % (GetDownloadSite(), _GetDownloadPlatform()) - return urllib.urlopen(url).read() - - -def DownloadChrome(revision, dest_dir, site=Site.CHROMIUM_SNAPSHOT): - """Downloads the packaged Chrome from the archive to the given directory. - - Args: - revision: the revision of Chrome to download. - dest_dir: the directory to download Chrome to. - site: the archive site to download from, default to the snapshot one. - - Returns: - The path to the unzipped Chrome binary. - """ - def GetZipName(revision): - if util.IsWindows(): - return revision + ( - '/chrome-win.zip' if int(revision) > 591478 else '/chrome-win32.zip') - elif util.IsMac(): - return revision + '/chrome-mac.zip' - elif util.IsLinux(): - return revision + '/chrome-linux.zip' - - def GetDirName(revision): - if util.IsWindows(): - return 'chrome-win' if int(revision) > 591478 else 'chrome-win32' - elif util.IsMac(): - return 'chrome-mac' - elif util.IsLinux(): - return 'chrome-linux' - - def GetChromePathFromPackage(): - if util.IsWindows(): - return 'chrome.exe' - elif util.IsMac(): - return 'Chromium.app/Contents/MacOS/Chromium' - elif util.IsLinux(): - return 'chrome-wrapper' - - zip_path = os.path.join(dest_dir, 'chrome-%s.zip' % revision) - if not os.path.exists(zip_path): - url = site + '/%s/%s' % (_GetDownloadPlatform(), GetZipName(revision)) - print 'Downloading', url, '...' - urllib.urlretrieve(url, zip_path) - util.Unzip(zip_path, dest_dir) - return os.path.join(dest_dir, GetDirName(revision), - GetChromePathFromPackage()) - - -def _GetDownloadPlatform(): - """Returns the name for this platform on the archive site.""" - if util.IsWindows(): - return 'Win' - elif util.IsMac(): - return 'Mac' - elif util.IsLinux(): - return 'Linux_x64' - - -def GetLatestSnapshotPosition(): - """Returns the latest commit position of snapshot build.""" - latest_revision = GetLatestRevision() - return latest_revision - - -def GetDownloadSite(): - """Returns the site to download snapshot build according to the platform.""" - return Site.CHROMIUM_SNAPSHOT - - -def GetCommitPositionFromGitHash(snapshot_hashcode): - json_url = GS_GIT_LOG_URL % snapshot_hashcode - try: - response = urllib2.urlopen(json_url) - except urllib2.HTTPError as error: - util.PrintAndFlush('HTTP Error %d' % error.getcode()) - return None - except urllib2.URLError as error: - util.PrintAndFlush('URL Error %s' % error.message) - return None - data = json.loads(response.read()[4:]) - if 'message' in data: - message = data['message'].split('\n') - message = [line for line in message if line.strip()] - search_pattern = re.compile(GS_SEARCH_PATTERN) - result = search_pattern.search(message[len(message)-1]) - if result: - return result.group(1) - util.PrintAndFlush('Failed to get commit position number for %s' % - snapshot_hashcode) - return None - - -def _GetGitHashFromCommitPosition(commit_position): - json_url = CR_REV_URL % commit_position - try: - response = urllib2.urlopen(json_url) - except urllib2.HTTPError as error: - util.PrintAndFlush('HTTP Error %d' % error.getcode()) - return None - except urllib2.URLError as error: - util.PrintAndFlush('URL Error %s' % error.message) - return None - data = json.loads(response.read()) - if 'git_sha' in data: - return data['git_sha'] - util.PrintAndFlush('Failed to get git hash for %s' % commit_position) - return None - - -def _GetFirstBuildAfterBranch(branch_position): - latest_revision = GetLatestSnapshotPosition() - for commit_position in range(int(branch_position), int(latest_revision)): - git_hash = _GetGitHashFromCommitPosition(commit_position) - try: - _ = DownloadChrome(git_hash, util.MakeTempDir(), GetDownloadSite()) - return git_hash - except: - continue - return None
diff --git a/chrome/test/chromedriver/chrome/ui_events.cc b/chrome/test/chromedriver/chrome/ui_events.cc index 2e7e6db9..c44ebfd 100644 --- a/chrome/test/chromedriver/chrome/ui_events.cc +++ b/chrome/test/chromedriver/chrome/ui_events.cc
@@ -23,6 +23,7 @@ modifiers(modifiers), buttons(buttons), click_count(click_count), + origin(kViewPort), element_id(std::string()), pointer_type(kMouse) {} @@ -34,12 +35,14 @@ : type(type), x(x), y(y), + origin(kViewPort), radiusX(1.0), radiusY(1.0), rotationAngle(0.0), force(1.0), id(0), - element_id(std::string()) {} + element_id(std::string()), + dispatch(true) {} TouchEvent::TouchEvent(const TouchEvent& other) = default;
diff --git a/chrome/test/chromedriver/chrome/ui_events.h b/chrome/test/chromedriver/chrome/ui_events.h index cfa3201e..dc44d43 100644 --- a/chrome/test/chromedriver/chrome/ui_events.h +++ b/chrome/test/chromedriver/chrome/ui_events.h
@@ -32,6 +32,9 @@ // Specifies the event's pointer type. enum PointerType { kMouse = 0, kPen }; +// Specifies the origin of pointer location. +enum OriginType { kViewPort, kPointer, kElement }; + struct MouseEvent { MouseEvent(MouseEventType type, MouseButton button, @@ -51,6 +54,7 @@ int buttons; // |click_count| should not be negative. int click_count; + OriginType origin; std::string element_id; PointerType pointer_type; }; @@ -74,12 +78,14 @@ TouchEventType type; int x; int y; + OriginType origin; double radiusX; double radiusY; double rotationAngle; double force; int id; std::string element_id; + bool dispatch; }; // Specifies the type of the keyboard event.
diff --git a/chrome/test/chromedriver/run_buildbot_steps.py b/chrome/test/chromedriver/run_buildbot_steps.py deleted file mode 100755 index 8844b520..0000000 --- a/chrome/test/chromedriver/run_buildbot_steps.py +++ /dev/null
@@ -1,302 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 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. - -"""Runs all the buildbot steps for ChromeDriver except for update/compile.""" - -import glob -import json -import optparse -import os -import sys -import tempfile -import time - -_THIS_DIR = os.path.abspath(os.path.dirname(__file__)) -GS_CHROMEDRIVER_DATA_BUCKET = 'gs://chromedriver-data' -GS_CONTINUOUS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/continuous' -GS_PREBUILTS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/prebuilts' -GS_SERVER_LOGS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/server_logs' -SERVER_LOGS_LINK = ( - 'http://chromedriver-data.storage.googleapis.com/server_logs') -TEST_LOG_FORMAT = '%s_log.json' - -SCRIPT_DIR = os.path.join(_THIS_DIR, os.pardir, os.pardir, os.pardir, os.pardir, - os.pardir, os.pardir, os.pardir, 'scripts') -SITE_CONFIG_DIR = os.path.join(_THIS_DIR, os.pardir, os.pardir, os.pardir, - os.pardir, os.pardir, os.pardir, os.pardir, - 'site_config') -sys.path.append(SCRIPT_DIR) -sys.path.append(SITE_CONFIG_DIR) - -import archive -import chrome_paths -from slave import gsutil_download -from slave import slave_utils -import util - - -def _ArchivePrebuilts(commit_position): - """Uploads the prebuilts to google storage.""" - util.MarkBuildStepStart('archive prebuilts') - zip_path = util.Zip(os.path.join(chrome_paths.GetBuildDir(['chromedriver']), - 'chromedriver')) - if slave_utils.GSUtilCopy( - zip_path, - '%s/%s' % (GS_PREBUILTS_URL, 'r%s.zip' % commit_position)): - util.MarkBuildStepError() - - -def _ArchiveServerLogs(): - """Uploads chromedriver server logs to google storage.""" - util.MarkBuildStepStart('archive chromedriver server logs') - pathname_pattern = os.path.join(tempfile.gettempdir(), 'chromedriver_log_*') - print 'archiving logs from: %s' % pathname_pattern - for server_log in glob.glob(pathname_pattern): - if os.path.isfile(server_log): - base_name = os.path.basename(server_log) - util.AddLink(base_name, '%s/%s' % (SERVER_LOGS_LINK, base_name)) - slave_utils.GSUtilCopy( - server_log, - '%s/%s' % (GS_SERVER_LOGS_URL, base_name), - mimetype='text/plain') - - -def _DownloadPrebuilts(): - """Downloads the most recent prebuilts from google storage.""" - util.MarkBuildStepStart('Download latest chromedriver') - - zip_path = os.path.join(util.MakeTempDir(), 'build.zip') - if gsutil_download.DownloadLatestFile(GS_PREBUILTS_URL, - GS_PREBUILTS_URL + '/r', - zip_path): - util.MarkBuildStepError() - - util.Unzip(zip_path, chrome_paths.GetBuildDir(['host_forwarder'])) - - -def _GetTestResultsLog(platform): - """Gets the test results log for the given platform. - - Args: - platform: The platform that the test results log is for. - - Returns: - A dictionary where the keys are commit positions and the values are booleans - indicating whether the tests passed. - """ - (temp_fd, temp_log) = tempfile.mkstemp() - os.close(temp_fd) - log_name = TEST_LOG_FORMAT % platform - result = slave_utils.GSUtilDownloadFile( - '%s/%s' % (GS_CHROMEDRIVER_DATA_BUCKET, log_name), temp_log) - if result: - return {} - with open(temp_log, 'rb') as log_file: - json_dict = json.load(log_file) - # Workaround for json encoding dictionary keys as strings. - return dict([(int(v[0]), v[1]) for v in json_dict.items()]) - - -def _PutTestResultsLog(platform, test_results_log): - """Pushes the given test results log to google storage.""" - temp_dir = util.MakeTempDir() - log_name = TEST_LOG_FORMAT % platform - log_path = os.path.join(temp_dir, log_name) - with open(log_path, 'wb') as log_file: - json.dump(test_results_log, log_file) - if slave_utils.GSUtilCopyFile(log_path, GS_CHROMEDRIVER_DATA_BUCKET): - raise Exception('Failed to upload test results log to google storage') - - -def _UpdateTestResultsLog(platform, commit_position, passed): - """Updates the test results log for the given platform. - - Args: - platform: The platform name. - commit_position: The commit position number. - passed: Boolean indicating whether the tests passed at this commit position. - """ - - assert commit_position.isdigit(), 'The commit position must be a number' - commit_position = int(commit_position) - log = _GetTestResultsLog(platform) - if len(log) > 500: - del log[min(log.keys())] - assert commit_position not in log, \ - 'Results already exist for commit position %s' % commit_position - log[commit_position] = bool(passed) - _PutTestResultsLog(platform, log) - - -def _GetSupportedChromeVersions(): - """Get the minimum and maximum supported Chrome versions. - - Returns: - A tuple of the form (min_version, max_version). - """ - # Minimum supported Chrome version is embedded as: - # const int kMinimumSupportedChromeVersion[] = {27, 0, 1453, 0}; - with open(os.path.join(_THIS_DIR, 'chrome', 'version.cc'), 'r') as f: - lines = f.readlines() - chrome_min_version_line = [ - x for x in lines if 'kMinimumSupportedChromeVersion' in x] - chrome_min_version = chrome_min_version_line[0].split('{')[1].split(',')[0] - with open(os.path.join(chrome_paths.GetSrc(), 'chrome', 'VERSION'), 'r') as f: - chrome_max_version = f.readlines()[0].split('=')[1].strip() - return (chrome_min_version, chrome_max_version) - - -def _ArchiveGoodBuild(platform, commit_position): - """Archive chromedriver binary if the build is green.""" - assert platform != 'android' - util.MarkBuildStepStart('archive build') - - server_name = 'chromedriver' - if util.IsWindows(): - server_name += '.exe' - zip_path = util.Zip(os.path.join(chrome_paths.GetBuildDir([server_name]), - server_name)) - - build_name = 'chromedriver_%s_%s.zip' % ( - platform, commit_position) - build_url = '%s/%s' % (GS_CONTINUOUS_URL, build_name) - if slave_utils.GSUtilCopy(zip_path, build_url): - util.MarkBuildStepError() - - if util.IsWindows(): - zip_path = util.Zip(os.path.join( - chrome_paths.GetBuildDir([server_name + '.pdb']), server_name + '.pdb')) - pdb_name = 'chromedriver_%s_pdb_%s.zip' % ( - platform, commit_position) - pdb_url = '%s/%s' % (GS_CONTINUOUS_URL, pdb_name) - if slave_utils.GSUtilCopy(zip_path, pdb_url): - util.MarkBuildStepError() - - (latest_fd, latest_file) = tempfile.mkstemp() - os.write(latest_fd, build_name) - os.close(latest_fd) - latest_url = '%s/latest_%s' % (GS_CONTINUOUS_URL, platform) - if slave_utils.GSUtilCopy(latest_file, latest_url, mimetype='text/plain'): - util.MarkBuildStepError() - os.remove(latest_file) - - -def _WaitForLatestSnapshot(commit_position): - util.MarkBuildStepStart('wait_for_snapshot') - for attempt in range(0, 200): - snapshot_position = archive.GetLatestSnapshotPosition() - if commit_position is not None and snapshot_position is not None: - if int(snapshot_position) >= int(commit_position): - break - util.PrintAndFlush('Waiting for snapshot >= %s, found %s' % - (commit_position, snapshot_position)) - time.sleep(60) - if int(snapshot_position) < int(commit_position): - raise Exception('Failed to find a snapshot version >= %s' % commit_position) - util.PrintAndFlush('Got snapshot commit position %s' % snapshot_position) - - -def _AddToolsToPath(platform_name): - """Add some tools like Ant and Java to PATH for testing steps to use.""" - paths = [] - error_message = '' - if platform_name == 'win32': - paths = [ - # Path to Ant and Java, required for the java acceptance tests. - 'C:\\Program Files (x86)\\Java\\ant\\bin', - 'C:\\Program Files (x86)\\Java\\jre\\bin', - ] - error_message = ('Java test steps will fail as expected and ' - 'they can be ignored.\n' - 'Ant, Java or others might not be installed on bot.\n' - 'Please refer to page "WATERFALL" on site ' - 'go/chromedriver.') - if paths: - util.MarkBuildStepStart('Add tools to PATH') - path_missing = False - for path in paths: - if not os.path.isdir(path) or not os.listdir(path): - print 'Directory "%s" is not found or empty.' % path - path_missing = True - if path_missing: - print error_message - util.MarkBuildStepError() - return - os.environ['PATH'] += os.pathsep + os.pathsep.join(paths) - - -def main(): - parser = optparse.OptionParser() - parser.add_option( - '', '--android-packages', - help=('Comma separated list of application package names, ' - 'if running tests on Android.')) - parser.add_option( - '-r', '--revision', help='Chromium git revision hash') - parser.add_option( - '', '--update-log', action='store_true', - help='Update the test results log (only applicable to Android)') - options, _ = parser.parse_args() - - bitness = '32' - if util.Is64Bit(): - bitness = '64' - platform = '%s%s' % (util.GetPlatformName(), bitness) - if options.android_packages: - platform = 'android' - - if not options.revision: - commit_position = None - else: - commit_position = archive.GetCommitPositionFromGitHash(options.revision) - if commit_position is None: - raise Exception('Failed to convert revision to commit position') - - if platform == 'android': - if not options.revision and options.update_log: - parser.error('Must supply a --revision with --update-log') - _DownloadPrebuilts() - else: - if not options.revision: - parser.error('Must supply a --revision') - if platform == 'linux64': - _ArchivePrebuilts(commit_position) - _WaitForLatestSnapshot(commit_position) - - _AddToolsToPath(platform) - - cmd = [ - sys.executable, - os.path.join(_THIS_DIR, 'test', 'run_all_tests.py'), - ] - if platform == 'android': - cmd.append('--android-packages=' + options.android_packages) - - passed = (util.RunCommand(cmd) == 0) - - _ArchiveServerLogs() - - if platform == 'android': - if options.update_log: - util.MarkBuildStepStart('update test result log') - _UpdateTestResultsLog(platform, commit_position, passed) - elif passed: - _ArchiveGoodBuild(platform, commit_position) - - if not passed: - # Make sure the build is red if there is some uncaught exception during - # running run_all_tests.py. - util.MarkBuildStepStart('run_all_tests.py') - util.MarkBuildStepError() - - # Add a "cleanup" step so that errors from runtest.py or bb_device_steps.py - # (which invoke this script) are kept in their own build step. - util.MarkBuildStepStart('cleanup') - - return 0 if passed else 1 - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py deleted file mode 100755 index cca595e..0000000 --- a/chrome/test/chromedriver/test/run_all_tests.py +++ /dev/null
@@ -1,204 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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. - -"""Runs all ChromeDriver end to end tests.""" - -import optparse -import os -import platform -import shutil -import sys -import tempfile -import traceback - -_THIS_DIR = os.path.abspath(os.path.dirname(__file__)) -_PARENT_DIR = os.path.join(_THIS_DIR, os.pardir) -sys.path.insert(0, _PARENT_DIR) - -import archive -import chrome_paths -import util - -sys.path.insert(0, os.path.join(chrome_paths.GetSrc(), 'build', 'android')) -from pylib import constants - - -def _GenerateTestCommand(script, - chromedriver, - chrome=None, - android_package=None, - verbose=False): - _, log_path = tempfile.mkstemp(prefix='chromedriver_log_') - print 'chromedriver server log: %s' % log_path - cmd = [ - sys.executable, - os.path.join(_THIS_DIR, script), - '--chromedriver=%s' % chromedriver, - '--log-path=%s' % log_path, - ] - - if chrome: - cmd.append('--chrome=' + chrome) - - if verbose: - cmd.append('--verbose') - - if android_package: - cmd = ['xvfb-run', '-a'] + cmd - cmd.append('--android-package=' + android_package) - return cmd - - -def RunReplayTests(chromedriver, chrome): - util.MarkBuildStepStart('replay_tests') - - _, log_path = tempfile.mkstemp(prefix='chromedriver_log_') - print 'chromedriver server log: %s' % log_path - cmd = [ - sys.executable, - os.path.join(_PARENT_DIR, 'log_replay', 'client_replay_test.py'), - chromedriver, - chrome, - '--output-log-path=%s' % log_path - ] - code = util.RunCommand(cmd) - - if code: - util.MarkBuildStepError() - return code - - -def RunPythonTests(chromedriver, - chrome=None, - android_package=None): - util.MarkBuildStepStart('python_tests') - code = util.RunCommand( - _GenerateTestCommand('run_py_tests.py', - chromedriver, - chrome=chrome, - android_package=android_package)) - if code: - util.MarkBuildStepError() - return code - - -def RunJavaTests(chromedriver, chrome=None, - android_package=None, - verbose=False): - util.MarkBuildStepStart('java_tests') - code = util.RunCommand( - _GenerateTestCommand('run_java_tests.py', - chromedriver, - chrome=chrome, - android_package=android_package, - verbose=verbose)) - if code: - util.MarkBuildStepError() - return code - - -def RunCppTests(cpp_tests): - util.MarkBuildStepStart('chromedriver_tests') - code = util.RunCommand([cpp_tests]) - if code: - util.MarkBuildStepError() - return code - - -def DownloadChrome(version_name, revision, download_site): - util.MarkBuildStepStart('download %s' % version_name) - try: - temp_dir = util.MakeTempDir() - return (temp_dir, archive.DownloadChrome(revision, temp_dir, download_site)) - except Exception: - traceback.print_exc() - util.AddBuildStepText('Skip Java and Python tests') - util.MarkBuildStepError() - return (None, None) - - -def _KillChromes(): - chrome_map = { - 'win': 'chrome.exe', - 'mac': 'Chromium', - 'linux': 'chrome', - } - if util.IsWindows(): - cmd = ['taskkill', '/F', '/IM'] - else: - cmd = ['killall', '-9'] - cmd.append(chrome_map[util.GetPlatformName()]) - util.RunCommand(cmd) - - -def main(): - parser = optparse.OptionParser() - parser.add_option( - '', '--android-packages', - help='Comma separated list of application package names, ' - 'if running tests on Android.') - options, _ = parser.parse_args() - - exe_postfix = '' - if util.IsWindows(): - exe_postfix = '.exe' - cpp_tests_name = 'chromedriver_tests' + exe_postfix - server_name = 'chromedriver' + exe_postfix - - required_build_outputs = [server_name] - if not options.android_packages: - required_build_outputs += [cpp_tests_name] - try: - build_dir = chrome_paths.GetBuildDir(required_build_outputs) - except RuntimeError: - util.MarkBuildStepStart('check required binaries') - traceback.print_exc() - util.MarkBuildStepError() - constants.SetBuildType(os.path.basename(build_dir)) - print 'Using build outputs from', build_dir - - chromedriver = os.path.join(build_dir, server_name) - platform_name = util.GetPlatformName() - if util.IsLinux() and util.Is64Bit(): - platform_name += '64' - - if options.android_packages: - os.environ['PATH'] += os.pathsep + os.path.join( - _THIS_DIR, os.pardir, 'chrome') - code = 0 - for package in options.android_packages.split(','): - code1 = RunPythonTests(chromedriver, - chrome_version_name=package, - android_package=package) - code2 = RunJavaTests(chromedriver, - chrome_version_name=package, - android_package=package, - verbose=True) - code = code or code1 or code2 - return code - else: - code = 0 - download_site = archive.GetDownloadSite() - revision = archive.GetLatestRevision() - temp_dir, chrome_path = DownloadChrome(revision, revision, - download_site) - if not chrome_path: - code = 1 - code1 = RunPythonTests(chromedriver, - chrome=chrome_path) - code2 = RunJavaTests(chromedriver, - verbose=True, - chrome=chrome_path) - code3 = RunReplayTests(chromedriver, - chrome=chrome_path) - code = code or code1 or code2 or code3 - _KillChromes() - shutil.rmtree(temp_dir) - cpp_tests = os.path.join(build_dir, cpp_tests_name) - return RunCppTests(cpp_tests) or code - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/chrome/test/chromedriver/test/run_java_tests.py b/chrome/test/chromedriver/test/run_java_tests.py index 53fc7d8..7e94247 100755 --- a/chrome/test/chromedriver/test/run_java_tests.py +++ b/chrome/test/chromedriver/test/run_java_tests.py
@@ -3,13 +3,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Runs the WebDriver Java acceptance tests. - -This script is called from chrome/test/chromedriver/run_all_tests.py and reports -results using the buildbot annotation scheme. - -For ChromeDriver documentation, refer to http://code.google.com/p/chromedriver. -""" +"""Runs the WebDriver Java acceptance tests.""" import optparse import os
diff --git a/chrome/test/chromedriver/test/waterfall_builder_config_sample.json b/chrome/test/chromedriver/test/waterfall_builder_config_sample.json deleted file mode 100644 index 1ad85fe..0000000 --- a/chrome/test/chromedriver/test/waterfall_builder_config_sample.json +++ /dev/null
@@ -1,32 +0,0 @@ -{ - "build_info": { - "win7" : { - "builder_url" : "http://build.chromium.org/p/chromium.chromedriver/builders/Win7/builds/", - "json_url" : "http://build.chromium.org/p/chromium.chromedriver/json/builders/Win7/builds/%d?as_text=1", - "builds_url": "http://build.chromium.org/p/chromium.chromedriver/json/builders/Win7/builds/_all?as_text=1" - }, - "mac_10_6" : { - "builder_url" : "http://build.chromium.org/p/chromium.chromedriver/builders/Mac%2010.6/builds/", - "json_url" : "http://build.chromium.org/p/chromium.chromedriver/json/builders/Mac 10.6/builds/%d?as_text=1", - "builds_url": "http://build.chromium.org/p/chromium.chromedriver/json/builders/Mac 10.6/builds/_all?as_text=1" - }, - "linux" : { - "builder_url" : "http://build.chromium.org/p/chromium.chromedriver/builders/Linux/builds/", - "json_url" : "http://build.chromium.org/p/chromium.chromedriver/json/builders/Linux/builds/%d?as_text=1", - "builds_url": "http://build.chromium.org/p/chromium.chromedriver/json/builders/Linux/builds/_all?as_text=1" - }, - "linux32" : { - "builder_url" : "http://build.chromium.org/p/chromium.chromedriver/builders/Linux32/builds/", - "json_url" : "http://build.chromium.org/p/chromium.chromedriver/json/builders/Linux32/builds/%d?as_text=1", - "builds_url": "http://build.chromium.org/p/chromium.chromedriver/json/builders/Linux32/builds/_all?as_text=1" - }, - "android_chromedriver_test" : { - "builder_url" : "http://build.chromium.org/p/chromium.fyi/builders/Android%20ChromeDriver%20Tests%20%28dbg%29/builds/", - "json_url" : "http://build.chromium.org/p/chromium.fyi/json/builders/Android ChromeDriver Tests (dbg)/builds/%d?as_text=1", - "builds_url": "http://build.chromium.org/p/chromium.fyi/json/builders/Android ChromeDriver Tests (dbg)/builds/_all?as_text=1" - } - }, - "recipient_emails": "pshenoy@chromium.org", - "sender_email": "pshenoy@chromium.org", - "old_build_days": 2 -}
diff --git a/chrome/test/chromedriver/test/waterfall_builder_monitor.py b/chrome/test/chromedriver/test/waterfall_builder_monitor.py deleted file mode 100755 index ba8ec533..0000000 --- a/chrome/test/chromedriver/test/waterfall_builder_monitor.py +++ /dev/null
@@ -1,226 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. - -"""Waterfall monitoring script. - This script checks all builders specified in the config file and sends - status email about any step failures in these builders. This also - reports a build as failure if the latest build on that builder was built - 2 days back. (Number of days can be configured in the config file) - - This script can be run as cronjob on a linux machine once a day and - get email notification for any waterfall specified in the config file. - - Sample cronjob entry below. This entry will run the script everyday at 9 AM. - Include this in the crontab file. - 0 9 * * * <Path to script> --config <Path to json file> -""" - -import datetime -import json -import optparse -import sys -import time -import traceback -import urllib - -from datetime import timedelta -from email.mime.text import MIMEText -from subprocess import Popen, PIPE - - -SUCCESS_SUBJECT = ('[CHROME TESTING]: Builder status %s: PASSED.') -FAILURE_SUBJECT = ('[CHROME TESTING]: Builder status %s: FAILED %d out of %d') -EXCEPTION_SUBJECT = ('Exception occurred running waterfall_builder_monitor.py ' - 'script') - - -def GetTimeDelta(date, days): - if isinstance(date, datetime.datetime): - return date + timedelta(days) - - -def GetDateFromEpochFormat(epoch_time): - last_build_date = time.localtime(epoch_time) - last_build_date = datetime.datetime(int(last_build_date.tm_year), - int(last_build_date.tm_mon), - int(last_build_date.tm_mday), - int(last_build_date.tm_hour), - int(last_build_date.tm_min), - int(last_build_date.tm_sec)) - return last_build_date - - -def GetJSONData(json_url): - response = urllib.urlopen(json_url) - if response.getcode() == 200: - try: - data = json.loads(response.read()) - except ValueError: - print 'ValueError for JSON URL: %s' % json_url - raise - else: - raise Exception('Error from URL: %s' % json_url) - response.close() - return data - - -def SendEmailViaSendmailCommand(sender_email, recipient_emails, - subject, email_body): - msg = MIMEText(email_body) - msg["From"] = sender_email - msg["To"] = recipient_emails - msg["Subject"] = subject - pipe = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE) - pipe.communicate(msg.as_string()) - - -def SendStatusEmailViaSendmailCommand(consolidated_results, - recipient_emails, - sender_email): - failure_count = 0 - for result in consolidated_results: - if result['error'] != 'passed' and not result['build_too_old']: - failure_count += 1 - today = str(datetime.date.today()).replace('-', '/')[5:] - if failure_count == 0: - subject = SUCCESS_SUBJECT % today - else: - subject = FAILURE_SUBJECT % (today, - failure_count, - len(consolidated_results)) - - email_body = '' - for result in consolidated_results: - if result['error'] != 'passed' or result['build_too_old']: - if result['build_date'] is not None: - email_body += result['platform'] + ': ' +\ - result['build_link'] + ' ( Build too old: ' +\ - result['build_date'] + ' ) ' +'\n\n' - else: - email_body += result['platform'] + ': ' +\ - result['build_link'] + '\n\n' - - SendEmailViaSendmailCommand(sender_email, recipient_emails, - subject, email_body) - - -def SendExceptionEmailViaSendmailCommand(exception_message_lines, - recipient_emails, - sender_email): - subject = EXCEPTION_SUBJECT - email_body = '' - email_body = '\n'.join(exception_message_lines) - - SendEmailViaSendmailCommand(sender_email, recipient_emails, - subject, email_body) - - -class OfficialBuilderParser(object): - """This class implements basic utility functions on a specified builder.""" - def __init__(self, builder_type, build_info): - self.platform = builder_type - self.builder_info = build_info - self.builder_url = build_info['builder_url'] - self.build_json_url = build_info['json_url'] - self.build = self._GetLatestBuildNumber() - - def _GetLatestBuildNumber(self): - json_url = self.builder_info['builds_url'] - data = GetJSONData(json_url) - # Get a sorted list of all the keys in the json data. - keys = sorted(map(int, data.keys())) - return self._GetLatestCompletedBuild(keys) - - def _GetLatestCompletedBuild(self, keys): - reversed_list = keys[::-1] - for build in reversed_list: - data = self._GetJSONDataForBuild(build) - if data is not None: - if 'text' in data: - return build - return None - - def _GetJSONDataForBuild(self, build): - if build is None: - return build - json_url = self.build_json_url % build - return GetJSONData(json_url) - - -class GetBuilderStatus(OfficialBuilderParser): - def __init__(self, builder_type, build_info): - OfficialBuilderParser.__init__(self, builder_type, build_info) - - def CheckForFailedSteps(self, days): - if self.build is None: - return {} - result = {'platform': self.platform, - 'build_number': self.build, - 'build_link': self.builder_url + str(self.build), - 'build_date': None, - 'build_too_old': False, - 'error': 'unknown'} - data = self._GetJSONDataForBuild(self.build) - if data is not None: - if 'text' in data: - if 'build' in data['text'] and 'successful' in data['text']: - result['error'] = 'passed' - else: - if 'failed' in data['text'] or\ - 'exception' in data['text'] or\ - 'interrupted' in data['text']: - result['error'] = 'failed' - if 'times' in data: - old_date = GetTimeDelta(datetime.datetime.now(), days) - last_build_date = GetDateFromEpochFormat(data['times'][0]) - if last_build_date < old_date: - result['build_too_old'] = True - result['build_date'] = str(last_build_date).split(' ')[0] - else: - raise Exception('There was some problem getting JSON data ' - 'from URL: %s' % result['build_link']) - return result - -def main(): - parser = optparse.OptionParser() - parser.add_option('--config', type='str', - help='Absolute path to the config file.') - - (options, _) = parser.parse_args() - if not options.config: - print 'Error: missing required parameter: --config' - parser.print_help() - return 1 - - try: - with open(options.config, 'r') as config_file: - try: - json_data = json.loads(config_file.read()) - except ValueError: - print 'ValueError for loading JSON data from : %s' % options.config - raise ValueError - - old_build_days = -2 - if 'old_build_days' in json_data: - old_build_days = - json_data['old_build_days'] - consolidated_results = [] - for key in json_data['build_info'].keys(): - builder_status = GetBuilderStatus(key, json_data['build_info'][key]) - builder_result = builder_status.CheckForFailedSteps(old_build_days) - consolidated_results.append(builder_result) - - SendStatusEmailViaSendmailCommand(consolidated_results, - json_data['recipient_emails'], - json_data['sender_email']) - return 0 - except Exception: - formatted_lines = traceback.format_exc().splitlines() - SendExceptionEmailViaSendmailCommand(formatted_lines, - json_data['recipient_emails'], - json_data['sender_email']) - return 1 - -if __name__ == '__main__': - sys.exit(main())
diff --git a/chrome/test/chromedriver/third_party/googlecode/LICENSE b/chrome/test/chromedriver/third_party/googlecode/LICENSE deleted file mode 100644 index 80a4762..0000000 --- a/chrome/test/chromedriver/third_party/googlecode/LICENSE +++ /dev/null
@@ -1,204 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2007-2009 Google Inc. - Copyright 2007-2009 WebDriver committers - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -
diff --git a/chrome/test/chromedriver/third_party/googlecode/README.chromium b/chrome/test/chromedriver/third_party/googlecode/README.chromium deleted file mode 100644 index dd64cfe9..0000000 --- a/chrome/test/chromedriver/third_party/googlecode/README.chromium +++ /dev/null
@@ -1,18 +0,0 @@ -Name: Google code support upload script -Short Name: googlecode_upload -URL: http://support.googlecode.com/svn/trunk/scripts/googlecode_upload.py -Version: r681 -Security Critical: no -License: Apache 2 -License File: NOT_SHIPPED - -Description: -A simple script from Google Code support for automating uploads. - -Local modifications: --Added comment describing license. They have a comment about the license, but -it uses an atypical format that isn't recognized by chromium's checklicense -script. --Instead of using the default netrc lookup which requires HOME to be set -(which normally isn't on Windows), specify the file using os.path.expanduser. --Fail instead of prompting for username/password if none is given.
diff --git a/chrome/test/chromedriver/third_party/googlecode/googlecode_upload.py b/chrome/test/chromedriver/third_party/googlecode/googlecode_upload.py deleted file mode 100755 index dec4eed..0000000 --- a/chrome/test/chromedriver/third_party/googlecode/googlecode_upload.py +++ /dev/null
@@ -1,240 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006, 2007 Google Inc. All Rights Reserved. -# Author: danderson@google.com (David Anderson) -# -# Script for uploading files to a Google Code project. -# -# This is intended to be both a useful script for people who want to -# streamline project uploads and a reference implementation for -# uploading files to Google Code projects. -# -# To upload a file to Google Code, you need to provide a path to the -# file on your local machine, a small summary of what the file is, a -# project name, and a valid account that is a member or owner of that -# project. You can optionally provide a list of labels that apply to -# the file. The file will be uploaded under the same name that it has -# in your local filesystem (that is, the "basename" or last path -# component). Run the script with '--help' to get the exact syntax -# and available options. -# -# Note that the upload script requests that you enter your -# googlecode.com password. This is NOT your Gmail account password! -# This is the password you use on googlecode.com for committing to -# Subversion and uploading files. You can find your password by going -# to http://code.google.com/hosting/settings when logged in with your -# Gmail account. If you have already committed to your project's -# Subversion repository, the script will automatically retrieve your -# credentials from there (unless disabled, see the output of '--help' -# for details). -# -# If you are looking at this script as a reference for implementing -# your own Google Code file uploader, then you should take a look at -# the upload() function, which is the meat of the uploader. You -# basically need to build a multipart/form-data POST request with the -# right fields and send it to https://PROJECT.googlecode.com/files . -# Authenticate the request using HTTP Basic authentication, as is -# shown below. -# -# Licensed under the terms of the Apache Software License 2.0: -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Questions, comments, feature requests and patches are most welcome. -# Please direct all of these to the Google Code users group: -# http://groups.google.com/group/google-code-hosting -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 - -"""Google Code file uploader script. -""" - -__author__ = 'danderson@google.com (David Anderson)' - -import httplib -import os.path -import optparse -import getpass -import base64 -import sys - - -def upload(file, project_name, user_name, password, summary, labels=None): - """Upload a file to a Google Code project's file server. - - Args: - file: The local path to the file. - project_name: The name of your project on Google Code. - user_name: Your Google account name. - password: The googlecode.com password for your account. - Note that this is NOT your global Google Account password! - summary: A small description for the file. - labels: an optional list of label strings with which to tag the file. - - Returns: a tuple: - http_status: 201 if the upload succeeded, something else if an - error occured. - http_reason: The human-readable string associated with http_status - file_url: If the upload succeeded, the URL of the file on Google - Code, None otherwise. - """ - # The login is the user part of user@gmail.com. If the login provided - # is in the full user@domain form, strip it down. - if user_name.endswith('@gmail.com'): - user_name = user_name[:user_name.index('@gmail.com')] - - form_fields = [('summary', summary)] - if labels is not None: - form_fields.extend([('label', l.strip()) for l in labels]) - - content_type, body = encode_upload_request(form_fields, file) - - upload_host = '%s.googlecode.com' % project_name - upload_uri = '/files' - auth_token = base64.b64encode('%s:%s'% (user_name, password)) - headers = { - 'Authorization': 'Basic %s' % auth_token, - 'User-Agent': 'Googlecode.com uploader v0.9.4', - 'Content-Type': content_type, - } - - server = httplib.HTTPSConnection(upload_host) - server.request('POST', upload_uri, body, headers) - resp = server.getresponse() - server.close() - - if resp.status == 201: - location = resp.getheader('Location', None) - else: - location = None - return resp.status, resp.reason, location - - -def encode_upload_request(fields, file_path): - """Encode the given fields and file into a multipart form body. - - fields is a sequence of (name, value) pairs. file is the path of - the file to upload. The file will be uploaded to Google Code with - the same file name. - - Returns: (content_type, body) ready for httplib.HTTP instance - """ - BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla' - CRLF = '\r\n' - - body = [] - - # Add the metadata about the upload first - for key, value in fields: - body.extend( - ['--' + BOUNDARY, - 'Content-Disposition: form-data; name="%s"' % key, - '', - value, - ]) - - # Now add the file itself - file_name = os.path.basename(file_path) - f = open(file_path, 'rb') - file_content = f.read() - f.close() - - body.extend( - ['--' + BOUNDARY, - 'Content-Disposition: form-data; name="filename"; filename="%s"' - % file_name, - # The upload server determines the mime-type, no need to set it. - 'Content-Type: application/octet-stream', - '', - file_content, - ]) - - # Finalize the form body - body.extend(['--' + BOUNDARY + '--', '']) - - return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body) - - -def upload_find_auth(file_path, project_name, summary, labels=None, - user_name=None, password=None, tries=3): - """Find credentials and upload a file to a Google Code project's file server. - - file_path, project_name, summary, and labels are passed as-is to upload. - - Args: - file_path: The local path to the file. - project_name: The name of your project on Google Code. - summary: A small description for the file. - labels: an optional list of label strings with which to tag the file. - config_dir: Path to Subversion configuration directory, 'none', or None. - user_name: Your Google account name. - tries: How many attempts to make. - """ - if user_name is None or password is None: - from netrc import netrc - # Chromium edit: Works on windows without requiring HOME to be set. - netrc_path = os.path.join(os.path.expanduser('~'), '.netrc') - authenticators = netrc(netrc_path).authenticators("code.google.com") - if authenticators: - if user_name is None: - user_name = authenticators[0] - if password is None: - password = authenticators[2] - - if user_name is None or password is None: - raise RuntimeError('Missing user credentials for upload') - - return upload(file_path, project_name, user_name, password, summary, labels) - - -def main(): - parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY ' - '-p PROJECT [options] FILE') - parser.add_option('-s', '--summary', dest='summary', - help='Short description of the file') - parser.add_option('-p', '--project', dest='project', - help='Google Code project name') - parser.add_option('-u', '--user', dest='user', - help='Your Google Code username') - parser.add_option('-w', '--password', dest='password', - help='Your Google Code password') - parser.add_option('-l', '--labels', dest='labels', - help='An optional list of comma-separated labels to attach ' - 'to the file') - - options, args = parser.parse_args() - - if not options.summary: - parser.error('File summary is missing.') - elif not options.project: - parser.error('Project name is missing.') - elif len(args) < 1: - parser.error('File to upload not provided.') - elif len(args) > 1: - parser.error('Only one file may be specified.') - - file_path = args[0] - - if options.labels: - labels = options.labels.split(',') - else: - labels = None - - status, reason, url = upload_find_auth(file_path, options.project, - options.summary, labels, - options.user, options.password) - if url: - print 'The file was uploaded successfully.' - print 'URL: %s' % url - return 0 - else: - print 'An error occurred. Your file was not uploaded.' - print 'Google Code upload server said: %s (%s)' % (reason, status) - return 1 - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc index 31f10966..283deeb8 100644 --- a/chrome/test/chromedriver/window_commands.cc +++ b/chrome/test/chromedriver/window_commands.cc
@@ -1334,6 +1334,7 @@ bool has_touch_start = false; int buttons = 0; std::string button_type; + OriginType origin_type = kPointer; std::string element_id; for (size_t j = 0; j < actions->GetSize(); j++) { const base::DictionaryValue* pointer_action; @@ -1344,10 +1345,18 @@ pointer_action->GetDouble("x", &x); pointer_action->GetDouble("y", &y); const base::DictionaryValue* origin_dict; + origin_type = kViewPort; element_id = ""; - if (pointer_action->HasKey("origin") && - pointer_action->GetDictionary("origin", &origin_dict)) { - origin_dict->GetString(GetElementKey(), &element_id); + if (pointer_action->HasKey("origin")) { + if (pointer_action->GetDictionary("origin", &origin_dict)) { + origin_type = kElement; + origin_dict->GetString(GetElementKey(), &element_id); + } else { + std::string origin; + pointer_action->GetString("origin", &origin); + if (origin == "pointer") + origin_type = kPointer; + } } } @@ -1360,6 +1369,7 @@ MouseEvent event(StringToMouseEventType(action_type), StringToMouseButton(button_type), x, y, 0, buttons, click_count); + event.origin = origin_type; event.element_id = element_id; event.pointer_type = StringToPointerType(pointer_type); mouse_events.push_back(event); @@ -1373,11 +1383,12 @@ else if (action_type == "pointerUp") has_touch_start = false; - if (action_type != "pointerMove" || has_touch_start) { - TouchEvent event(StringToTouchEventType(action_type), x, y); - event.element_id = element_id; - touch_events.push_back(event); - } + TouchEvent event(StringToTouchEventType(action_type), x, y); + event.origin = origin_type; + event.element_id = element_id; + if (action_type == "pointerMove") + event.dispatch = has_touch_start; + touch_events.push_back(event); } } @@ -1399,7 +1410,8 @@ size_t max_list_length = std::max({longest_mouse_list_size, longest_touch_list_size, longest_key_list_size, tick_durations.size()}); - std::map<std::string, gfx::Point> element_center_point; + std::vector<gfx::Point> mouse_locations(mouse_events_list.size()); + std::vector<gfx::Point> touch_locations(touch_events_list.size()); int key_modifiers = 0; for (size_t i = 0; i < max_list_length; i++) { std::list<KeyEvent> dispatch_key_events; @@ -1428,18 +1440,21 @@ if (i < mouse_events_list[j].size() && mouse_events_list[j][i].type != kPauseMouseEventType) { MouseEvent event = mouse_events_list[j][i]; - if (!event.element_id.empty()) { - if (event.type == kMovedMouseEventType || - element_center_point.find(event.element_id) == - element_center_point.end()) { + if (event.type == kMovedMouseEventType) { + if (event.origin == kPointer) { + event.x += mouse_locations[j].x(); + event.y += mouse_locations[j].y(); + } else if (!event.element_id.empty()) { int center_x = 0, center_y = 0; ElementInViewCenter(session, web_view, event.element_id, ¢er_x, ¢er_y); - element_center_point[event.element_id] = - gfx::Point(center_x, center_y); + event.x += center_x; + event.y += center_y; } - event.x += element_center_point[event.element_id].x(); - event.y += element_center_point[event.element_id].y(); + mouse_locations[j] = gfx::Point(event.x, event.y); + } else { + event.x = mouse_locations[j].x(); + event.y = mouse_locations[j].y(); } event.modifiers = key_modifiers; dispatch_mouse_events.push_back(event); @@ -1457,20 +1472,24 @@ if (i < touch_events_list[j].size() && touch_events_list[j][i].type != kPause) { TouchEvent event = touch_events_list[j][i]; - if (!event.element_id.empty()) { - if (event.type == kTouchMove || - element_center_point.find(event.element_id) == - element_center_point.end()) { + if (event.type == kTouchMove) { + if (event.origin == kPointer) { + event.x += touch_locations[j].x(); + event.y += touch_locations[j].y(); + } else if (!event.element_id.empty()) { int center_x = 0, center_y = 0; ElementInViewCenter(session, web_view, event.element_id, ¢er_x, ¢er_y); - element_center_point[event.element_id] = - gfx::Point(center_x, center_y); + event.x += center_x; + event.y += center_y; } - event.x += element_center_point[event.element_id].x(); - event.y += element_center_point[event.element_id].y(); + touch_locations[j] = gfx::Point(event.x, event.y); + } else { + event.x = touch_locations[j].x(); + event.y = touch_locations[j].y(); } - dispatch_touch_events.push_back(event); + if (event.dispatch) + dispatch_touch_events.push_back(event); } } if (dispatch_touch_events.size() > 0) {
diff --git a/chrome/test/data/android/render_tests/ExploreSitesPageTest.initial_layout.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ExploreSitesPageTest.initial_layout.Nexus_5-19.png.sha1 index a36c180f..03baa4792 100644 --- a/chrome/test/data/android/render_tests/ExploreSitesPageTest.initial_layout.Nexus_5-19.png.sha1 +++ b/chrome/test/data/android/render_tests/ExploreSitesPageTest.initial_layout.Nexus_5-19.png.sha1
@@ -1 +1 @@ -7847da096d38aa3d3204cdd37726a039b819e2ab \ No newline at end of file +9fb8c2552c167fae80da115358dbad6c9a21d43f \ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ExploreSitesPageTest.recycler_layout.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ExploreSitesPageTest.recycler_layout.Nexus_5-19.png.sha1 index 1c7a5c77..ff1bb65 100644 --- a/chrome/test/data/android/render_tests/ExploreSitesPageTest.recycler_layout.Nexus_5-19.png.sha1 +++ b/chrome/test/data/android/render_tests/ExploreSitesPageTest.recycler_layout.Nexus_5-19.png.sha1
@@ -1 +1 @@ -1801fe3bce2257fb2143548b99320b652c1bf033 \ No newline at end of file +8d1722f71ac07ab22c7c126b00e18deff42827f1 \ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ExploreSitesPageTest.scrolled_to_category_2.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ExploreSitesPageTest.scrolled_to_category_2.Nexus_5-19.png.sha1 index 9ead928..bd17bda 100644 --- a/chrome/test/data/android/render_tests/ExploreSitesPageTest.scrolled_to_category_2.Nexus_5-19.png.sha1 +++ b/chrome/test/data/android/render_tests/ExploreSitesPageTest.scrolled_to_category_2.Nexus_5-19.png.sha1
@@ -1 +1 @@ -41df775d3cc887efad3cc3ed14b010a50a4e6c63 \ No newline at end of file +abc2f7b73def0c35712eccc030ba6d13df454609 \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/image_writer_private/list_devices/test.js b/chrome/test/data/extensions/api_test/image_writer_private/list_devices/test.js index ec7be06..247fd8b 100644 --- a/chrome/test/data/extensions/api_test/image_writer_private/list_devices/test.js +++ b/chrome/test/data/extensions/api_test/image_writer_private/list_devices/test.js
@@ -41,4 +41,4 @@ }); } -chrome.test.runTests([testDeviceList]) +chrome.test.runTests([testDeviceList]);
diff --git a/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/content_script.js b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/content_script.js new file mode 100644 index 0000000..3ef78e1 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/content_script.js
@@ -0,0 +1,11 @@ +// Copyright 2019 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. + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request != 'worker->tab') { + chrome.test.sendMessage('FAILURE'); + return; + } + sendResponse('worker->tab->worker'); +});
diff --git a/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/manifest.json b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/manifest.json new file mode 100644 index 0000000..b222911 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/manifest.json
@@ -0,0 +1,13 @@ +{ + "name": "SW based extension: Messaging_WorkerToTab test", + "version": "0.1", + "manifest_version": 2, + "description": "chrome.tabs.sendMessage from extension SW.", + "permissions": ["tabs"], + "content_scripts": [{ + "matches": ["*://127.0.0.1:*/*"], + "run_at": "document_start", + "js": ["content_script.js"] + }], + "background": {"service_worker_script": "service_worker_background.js"} +}
diff --git a/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/service_worker_background.js b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/service_worker_background.js new file mode 100644 index 0000000..0396c26f --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/messaging/send_message_worker_to_tab/service_worker_background.js
@@ -0,0 +1,39 @@ +// Copyright 2019 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. + +var TEST_FILE_URL = 'http://127.0.0.1:PORT/extensions/test_file.html' + +chrome.test.getConfig((config) => { + var createdTabId = undefined; + chrome.test.runTests([ + function createTab() { + var testComplete = false; + chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) { + if (!createdTabId || tabId != createdTabId || + changeInfo.status !== 'complete') { + return; + } + chrome.tabs.onUpdated.removeListener(listener); + if (!testComplete) + chrome.test.succeed(); + }); + var testUrl = TEST_FILE_URL.replace(/PORT/, config.testServer.port); + chrome.tabs.create({url: testUrl}, function(tab) { + createdTabId = tab.id; + if (tab.status === 'complete') { + testComplete = true; + chrome.test.succeed(); + } + // Otherwise tabs.onUpdated will be called. + }); + }, + function testExternalMessage() { + chrome.tabs.sendMessage(createdTabId, 'worker->tab', function(response) { + console.log('response = ' + response); + chrome.test.assertEq('worker->tab->worker', response); + chrome.test.succeed(); + }); + }, + ]); +});
diff --git a/chrome/test/data/webui/settings/google_assistant_page_test.js b/chrome/test/data/webui/settings/google_assistant_page_test.js index 5958ac2..f8cf740 100644 --- a/chrome/test/data/webui/settings/google_assistant_page_test.js +++ b/chrome/test/data/webui/settings/google_assistant_page_test.js
@@ -9,6 +9,7 @@ constructor() { super([ 'showGoogleAssistantSettings', + 'retrainAssistantVoiceModel', ]); } @@ -16,6 +17,11 @@ showGoogleAssistantSettings() { this.methodCalled('showGoogleAssistantSettings'); } + + /** @override */ + retrainAssistantVoiceModel() { + this.methodCalled('retrainAssistantVoiceModel'); + } } suite('GoogleAssistantHandler', function() { @@ -26,6 +32,13 @@ /** @type {?TestGoogleAssistantBrowserProxy} */ let browserProxy = null; + suiteSetup(function() { + loadTimeData.overrideValues({ + enableAssistant: true, + voiceMatchEnabled: true, + }); + }); + setup(function() { browserProxy = new TestGoogleAssistantBrowserProxy(); settings.GoogleAssistantBrowserProxyImpl.instance_ = browserProxy; @@ -63,6 +76,7 @@ let button = page.$$('#googleAssistantContextEnable'); assertFalse(!!button); page.setPrefValue('settings.voice_interaction.enabled', true); + page.setPrefValue('settings.voice_interaction.context.enabled', false); Polymer.dom.flush(); button = page.$$('#googleAssistantContextEnable'); assertTrue(!!button); @@ -72,6 +86,123 @@ button.click(); Polymer.dom.flush(); assertTrue(button.checked); + assertTrue( + page.getPref('settings.voice_interaction.context.enabled.value'), true); + }); + + test('toggleAssistantHotword', function() { + let button = page.$$('#googleAssistantHotwordEnable'); + assertFalse(!!button); + page.setPrefValue('settings.voice_interaction.enabled', true); + page.setPrefValue('settings.voice_interaction.hotword.enabled', false); + Polymer.dom.flush(); + button = page.$$('#googleAssistantHotwordEnable'); + assertTrue(!!button); + assertFalse(button.disabled); + assertFalse(button.checked); + + button.click(); + Polymer.dom.flush(); + assertTrue(button.checked); + assertTrue( + page.getPref('settings.voice_interaction.hotword.enabled.value'), true); + }); + + test('tapOnRetrainVoiceModel', function() { + let button = page.$$('#retrainVoiceModel'); + assertFalse(!!button); + page.setPrefValue('settings.voice_interaction.enabled', true); + page.setPrefValue('settings.voice_interaction.hotword.enabled', true); + page.setPrefValue( + 'settings.voice_interaction.activity_control.consent_status', + ConsentStatus.kActivityControlAccepted); + Polymer.dom.flush(); + button = page.$$('#retrainVoiceModel'); + assertTrue(!!button); + + button.click(); + Polymer.dom.flush(); + return browserProxy.whenCalled('retrainAssistantVoiceModel'); + }); + + test('retrainButtonVisibility', function() { + let button = page.$$('#retrainVoiceModel'); + assertFalse(!!button); + page.setPrefValue('settings.voice_interaction.enabled', true); + Polymer.dom.flush(); + button = page.$$('#retrainVoiceModel'); + assertFalse(!!button); + + // Hotword enabled. + // Activity control consent not granted. + // Button should not be shown. + page.setPrefValue('settings.voice_interaction.hotword.enabled', true); + page.setPrefValue( + 'settings.voice_interaction.activity_control.consent_status', + ConsentStatus.kUnauthorized); + Polymer.dom.flush(); + button = page.$$('#retrainVoiceModel'); + assertFalse(!!button); + + // Hotword disabled. + // Activity control consent granted. + // Button should not be shown. + page.setPrefValue('settings.voice_interaction.hotword.enabled', false); + page.setPrefValue( + 'settings.voice_interaction.activity_control.consent_status', + ConsentStatus.kActivityControlAccepted); + Polymer.dom.flush(); + button = page.$$('#retrainVoiceModel'); + assertFalse(!!button); + + // Hotword enabled. + // Activity control consent granted. + // Button should be shown. + page.setPrefValue('settings.voice_interaction.hotword.enabled', true); + page.setPrefValue( + 'settings.voice_interaction.activity_control.consent_status', + ConsentStatus.kActivityControlAccepted); + Polymer.dom.flush(); + button = page.$$('#retrainVoiceModel'); + assertTrue(!!button); + }); + + test('toggleAssistantNotification', function() { + let button = page.$$('#googleAssistantNotificationEnable'); + assertFalse(!!button); + page.setPrefValue('settings.voice_interaction.enabled', true); + page.setPrefValue('settings.voice_interaction.notification.enabled', false); + Polymer.dom.flush(); + button = page.$$('#googleAssistantNotificationEnable'); + assertTrue(!!button); + assertFalse(button.disabled); + assertFalse(button.checked); + + button.click(); + Polymer.dom.flush(); + assertTrue(button.checked); + assertTrue( + page.getPref('settings.voice_interaction.notification.enabled.value'), + true); + }); + + test('toggleAssistantLaunchWithMicOpen', function() { + let button = page.$$('#googleAssistantLaunchWithMicOpen'); + assertFalse(!!button); + page.setPrefValue('settings.voice_interaction.enabled', true); + page.setPrefValue('settings.voice_interaction.launch_with_mic_open', false); + Polymer.dom.flush(); + button = page.$$('#googleAssistantLaunchWithMicOpen'); + assertTrue(!!button); + assertFalse(button.disabled); + assertFalse(button.checked); + + button.click(); + Polymer.dom.flush(); + assertTrue(button.checked); + assertTrue( + page.getPref('settings.voice_interaction.launch_with_mic_open.value'), + true); }); test('tapOnAssistantSettings', function() {
diff --git a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js index f12fd36..476e4d8 100644 --- a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js +++ b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
@@ -31,6 +31,12 @@ }); var sessionTypeToRequest = sessionTypes.IMMERSIVE; +var referenceSpaceMap = { + [sessionTypes.IMMERSIVE]: { type: 'stationary', subtype: 'eye-level' }, + [sessionTypes.MAGIC_WINDOW]: { type: 'identity' }, + [sessionTypes.AR]: { type: 'identity' } +} + class SessionInfo { constructor() { this.session = null; @@ -134,7 +140,7 @@ } session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) }); - session.requestReferenceSpace({ type: 'stationary', subtype: 'eye-level' }) + session.requestReferenceSpace(referenceSpaceMap[getSessionType(session)]) .then( (refSpace) => { sessionInfos[getSessionType(session)].currentRefSpace = refSpace; session.requestAnimationFrame(onXRFrame);
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni index e5bf713..e9c0aba 100644 --- a/chromecast/chromecast.gni +++ b/chromecast/chromecast.gni
@@ -40,6 +40,10 @@ # still be used to enable multizone. supports_multizone = is_cast_audio_only && !is_cast_desktop_build + # Set to true on devices where the VolumeControl implementation is in the + # libcast_avsettings_1.0.so instead of in libcast_media_1.0.so. + cast_volume_control_in_avsettings = false + # Set to true for builds targeting ARC. is_android_arc = false
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn index 78d67d1..43547f13 100644 --- a/chromecast/media/BUILD.gn +++ b/chromecast/media/BUILD.gn
@@ -37,6 +37,10 @@ deps = [ "//chromecast/media/cma/backend:libcast_media_1.0", ] + + if (cast_volume_control_in_avsettings) { + deps += [ "//chromecast/media/avsettings:libcast_avsettings_1.0" ] + } } }
diff --git a/chromecast/media/avsettings/BUILD.gn b/chromecast/media/avsettings/BUILD.gn new file mode 100644 index 0000000..dc01162 --- /dev/null +++ b/chromecast/media/avsettings/BUILD.gn
@@ -0,0 +1,39 @@ +# Copyright 2019 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("//build/buildflag_header.gni") +import("//chromecast/chromecast.gni") + +buildflag_header("avsettings_buildflags") { + header = "avsettings_buildflags.h" + + flags = [ + "VOLUME_CONTROL_IN_AVSETTINGS_SHLIB=$cast_volume_control_in_avsettings", + ] +} + +cast_source_set("avsettings_dummy") { + sources = [ + "avsettings_dummy.cc", + "avsettings_dummy.h", + ] + + deps = [ + "//chromecast/public", + ] +} + +# Target for OEM partners to override avsettings shared library, i.e. +# libcast_avsettings_1.0.so. +cast_shared_library("libcast_avsettings_1.0") { + sources = [ + "avsettings_shlib.cc", + ] + + deps = [ + ":avsettings_buildflags", + ":avsettings_dummy", + "//chromecast/public", + ] +}
diff --git a/chromecast/media/avsettings/avsettings_dummy.cc b/chromecast/media/avsettings/avsettings_dummy.cc new file mode 100644 index 0000000..6c94092 --- /dev/null +++ b/chromecast/media/avsettings/avsettings_dummy.cc
@@ -0,0 +1,108 @@ +// Copyright 2019 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/avsettings/avsettings_dummy.h" + +namespace chromecast { + +AvSettingsDummy::AvSettingsDummy() : delegate_(nullptr) {} + +AvSettingsDummy::~AvSettingsDummy() = default; + +void AvSettingsDummy::Initialize(Delegate* delegate) { + delegate_ = delegate; +} + +void AvSettingsDummy::Finalize() { + delegate_ = nullptr; +} + +AvSettings::ActiveState AvSettingsDummy::GetActiveState() { + return ActiveState::UNKNOWN; +} + +bool AvSettingsDummy::TurnActive(bool switch_to_cast) { + return false; +} + +bool AvSettingsDummy::TurnStandby() { + return false; +} + +bool AvSettingsDummy::KeepSystemAwake(int time_millis) { + return false; +} + +AvSettings::AudioVolumeControlType +AvSettingsDummy::GetAudioVolumeControlType() { + return MASTER_VOLUME; +} + +bool AvSettingsDummy::GetAudioVolumeStepInterval(float* step_interval) { + return false; // Use default intervals per control type +} + +int AvSettingsDummy::GetAudioCodecsSupported() { + return 0; +} + +int AvSettingsDummy::GetMaxAudioChannels(AudioCodec codec) { + return 0; +} + +bool AvSettingsDummy::GetScreenResolution(int* width, int* height) { + return false; +} + +int AvSettingsDummy::GetHDCPVersion() { + return 0; +} + +int AvSettingsDummy::GetSupportedEotfs() { + return 0; +} + +int AvSettingsDummy::GetDolbyVisionFlags() { + return 0; +} + +int AvSettingsDummy::GetScreenWidthMm() { + return 0; +} + +int AvSettingsDummy::GetScreenHeightMm() { + return 0; +} + +bool AvSettingsDummy::GetOutputRestrictions(OutputRestrictions* restrictions) { + return false; +} + +void AvSettingsDummy::ApplyOutputRestrictions( + const OutputRestrictions& restrictions) {} + +AvSettings::WakeOnCastStatus AvSettingsDummy::GetWakeOnCastStatus() { + return WAKE_ON_CAST_NOT_SUPPORTED; +} + +bool AvSettingsDummy::EnableWakeOnCast(bool enabled) { + return false; +} + +AvSettings::HdrOutputType AvSettingsDummy::GetHdrOutputType() { + return HDR_OUTPUT_SDR; +} + +bool AvSettingsDummy::SetHdmiVideoMode(bool allow_4k, + int optimize_for_fps, + AvSettings::HdrOutputType output_type) { + return false; +} + +bool AvSettingsDummy::IsHdrOutputSupportedByCurrentHdmiVideoMode( + HdrOutputType output_type) { + return false; +} + +} // namespace chromecast
diff --git a/chromecast/media/avsettings/avsettings_dummy.h b/chromecast/media/avsettings/avsettings_dummy.h new file mode 100644 index 0000000..ffe7b6d --- /dev/null +++ b/chromecast/media/avsettings/avsettings_dummy.h
@@ -0,0 +1,56 @@ +// Copyright 2019 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_AVSETTINGS_AVSETTINGS_DUMMY_H_ +#define CHROMECAST_MEDIA_AVSETTINGS_AVSETTINGS_DUMMY_H_ + +#include "chromecast/public/avsettings.h" + +namespace chromecast { + +// Dummy implementation of AvSettings. +class AvSettingsDummy : public AvSettings { + public: + AvSettingsDummy(); + ~AvSettingsDummy() override; + + // AvSettings implementation: + void Initialize(Delegate* delegate) override; + void Finalize() override; + ActiveState GetActiveState() override; + bool TurnActive(bool switch_to_cast) override; + bool TurnStandby() override; + bool KeepSystemAwake(int time_millis) override; + AudioVolumeControlType GetAudioVolumeControlType() override; + bool GetAudioVolumeStepInterval(float* step_interval) override; + int GetAudioCodecsSupported() override; + int GetMaxAudioChannels(AudioCodec codec) override; + bool GetScreenResolution(int* width, int* height) override; + int GetHDCPVersion() override; + int GetSupportedEotfs() override; + int GetDolbyVisionFlags() override; + int GetScreenWidthMm() override; + int GetScreenHeightMm() override; + bool GetOutputRestrictions(OutputRestrictions* restrictions) override; + void ApplyOutputRestrictions(const OutputRestrictions& restrictions) override; + WakeOnCastStatus GetWakeOnCastStatus() override; + bool EnableWakeOnCast(bool enabled) override; + HdrOutputType GetHdrOutputType() override; + bool SetHdmiVideoMode(bool allow_4k, + int optimize_for_fps, + HdrOutputType output_type) override; + bool IsHdrOutputSupportedByCurrentHdmiVideoMode( + HdrOutputType output_type) override; + + private: + Delegate* delegate_; + + // Disallow copy and assign. + AvSettingsDummy(const AvSettingsDummy&) = delete; + AvSettingsDummy& operator=(const AvSettingsDummy&) = delete; +}; + +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_AVSETTINGS_AVSETTINGS_DUMMY_H_
diff --git a/chromecast/media/avsettings/avsettings_shlib.cc b/chromecast/media/avsettings/avsettings_shlib.cc new file mode 100644 index 0000000..9942302 --- /dev/null +++ b/chromecast/media/avsettings/avsettings_shlib.cc
@@ -0,0 +1,59 @@ +// Copyright 2019 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 <string> +#include <vector> + +#include "chromecast/media/avsettings/avsettings_buildflags.h" +#include "chromecast/media/avsettings/avsettings_dummy.h" +#include "chromecast/public/avsettings.h" +#include "chromecast/public/volume_control.h" + +namespace chromecast { + +// static +AvSettings* AvSettingsShlib::Create(const std::vector<std::string>& argv) { + return new AvSettingsDummy(); +} + +#if BUILDFLAG(VOLUME_CONTROL_IN_AVSETTINGS_SHLIB) +namespace media { + +void VolumeControl::Initialize(const std::vector<std::string>& argv) {} +void VolumeControl::Finalize() {} +void VolumeControl::AddVolumeObserver(VolumeObserver* observer) {} +void VolumeControl::RemoveVolumeObserver(VolumeObserver* observer) {} + +float VolumeControl::GetVolume(AudioContentType type) { + return 0.0f; +} + +void VolumeControl::SetVolume(VolumeChangeSource source, + AudioContentType type, + float level) {} + +bool VolumeControl::IsMuted(AudioContentType type) { + return false; +} + +void VolumeControl::SetMuted(VolumeChangeSource source, + AudioContentType type, + bool muted) {} + +void VolumeControl::SetOutputLimit(AudioContentType type, float limit) {} + +float VolumeControl::VolumeToDbFS(float volume) { + return 0.0f; +} + +float VolumeControl::DbFSToVolume(float db) { + return 0.0f; +} + +void VolumeControl::SetPowerSaveMode(bool power_save_on) {} + +} // namespace media +#endif // BUILDFLAG(VOLUME_CONTROL_IN_AVSETTINGS_SHLIB) + +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn index 0841728..f433fae 100644 --- a/chromecast/media/cma/backend/BUILD.gn +++ b/chromecast/media/cma/backend/BUILD.gn
@@ -82,16 +82,20 @@ ] deps = [ + ":audio_buildflags", "//chromecast/public", ] } +volume_control_in_media_shlib = !cast_volume_control_in_avsettings + buildflag_header("audio_buildflags") { header = "audio_buildflags.h" flags = [ "MEDIA_CLOCK_MONOTONIC_RAW=$media_clock_monotonic_raw", "SYSTEM_OWNS_VOLUME=$system_owns_volume", + "VOLUME_CONTROL_IN_MEDIA_SHLIB=$volume_control_in_media_shlib", ] }
diff --git a/chromecast/media/cma/backend/android/volume_control_android.cc b/chromecast/media/cma/backend/android/volume_control_android.cc index 95f0443..35a0898 100644 --- a/chromecast/media/cma/backend/android/volume_control_android.cc +++ b/chromecast/media/cma/backend/android/volume_control_android.cc
@@ -394,10 +394,5 @@ return GetVolumeControl().DbFSToVolumeCached(AudioContentType::kMedia, db); } -// static -void VolumeControl::SetPowerSaveMode(bool power_save_on) { - // Ignored. -} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/audio_output_redirector.cc b/chromecast/media/cma/backend/audio_output_redirector.cc index c2243d53..85ab26f 100644 --- a/chromecast/media/cma/backend/audio_output_redirector.cc +++ b/chromecast/media/cma/backend/audio_output_redirector.cc
@@ -118,11 +118,14 @@ void AudioOutputRedirector::AddInput(MixerInput* mixer_input) { if (ApplyToInput(mixer_input)) { inputs_[mixer_input] = std::make_unique<InputImpl>(this, mixer_input); + } else { + non_redirected_inputs_.insert(mixer_input); } } void AudioOutputRedirector::RemoveInput(MixerInput* mixer_input) { inputs_.erase(mixer_input); + non_redirected_inputs_.erase(mixer_input); } bool AudioOutputRedirector::ApplyToInput(MixerInput* mixer_input) { @@ -140,6 +143,33 @@ return false; } +void AudioOutputRedirector::UpdatePatterns( + std::vector<std::pair<AudioContentType, std::string>> patterns) { + config_.stream_match_patterns = std::move(patterns); + // Remove streams that no longer match. + for (auto it = inputs_.begin(); it != inputs_.end();) { + MixerInput* mixer_input = it->first; + if (!ApplyToInput(mixer_input)) { + non_redirected_inputs_.insert(mixer_input); + it = inputs_.erase(it); + } else { + ++it; + } + } + + // Add streams that previously didn't match. + for (auto it = non_redirected_inputs_.begin(); + it != non_redirected_inputs_.end();) { + MixerInput* mixer_input = *it; + if (ApplyToInput(mixer_input)) { + inputs_[mixer_input] = std::make_unique<InputImpl>(this, mixer_input); + it = non_redirected_inputs_.erase(it); + } else { + ++it; + } + } +} + void AudioOutputRedirector::Start(int output_samples_per_second) { output_->Start(output_samples_per_second); } @@ -221,8 +251,7 @@ AudioOutputRedirectorToken* CastMediaShlib::AddAudioOutputRedirection( const AudioOutputRedirectionConfig& config, std::unique_ptr<RedirectedAudioOutput> output) { - if (!output || config.num_output_channels <= 0 || - config.stream_match_patterns.empty()) { + if (!output || config.num_output_channels <= 0) { return nullptr; } @@ -243,5 +272,18 @@ } } +// static +void CastMediaShlib::ModifyAudioOutputRedirection( + AudioOutputRedirectorToken* token, + std::vector<std::pair<AudioContentType, std::string>> + stream_match_patterns) { + AudioOutputRedirector* redirector = + static_cast<AudioOutputRedirector*>(token); + if (redirector) { + StreamMixer::Get()->ModifyAudioOutputRedirection( + redirector, std::move(stream_match_patterns)); + } +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/audio_output_redirector.h b/chromecast/media/cma/backend/audio_output_redirector.h index 4d1b48d..c2ab65f 100644 --- a/chromecast/media/cma/backend/audio_output_redirector.h +++ b/chromecast/media/cma/backend/audio_output_redirector.h
@@ -8,6 +8,7 @@ #include <cstdint> #include <memory> #include <string> +#include <utility> #include <vector> #include "base/containers/flat_map.h" @@ -60,6 +61,12 @@ void AddInput(MixerInput* mixer_input); void RemoveInput(MixerInput* mixer_input); + // Updates the set of patterns used to determine which inputs should be + // redirected by this AudioOutputRedirector. Any inputs which no longer match + // will stop being redirected. + void UpdatePatterns( + std::vector<std::pair<AudioContentType, std::string>> patterns); + // Indicates that mixer output is starting at the given sample rate of // |output_samples_per_second|. void Start(int output_samples_per_second); @@ -88,7 +95,7 @@ bool ApplyToInput(MixerInput* mixer_input); - const AudioOutputRedirectionConfig config_; + AudioOutputRedirectionConfig config_; const std::unique_ptr<RedirectedAudioOutput> output_; int next_num_frames_ = 0; @@ -99,6 +106,7 @@ std::vector<float*> channel_data_; base::flat_map<MixerInput*, std::unique_ptr<InputImpl>> inputs_; + base::flat_set<MixerInput*> non_redirected_inputs_; DISALLOW_COPY_AND_ASSIGN(AudioOutputRedirector); };
diff --git a/chromecast/media/cma/backend/cast_media_android_dummy.cc b/chromecast/media/cma/backend/cast_media_android_dummy.cc index 46339609..d2b7b54 100644 --- a/chromecast/media/cma/backend/cast_media_android_dummy.cc +++ b/chromecast/media/cma/backend/cast_media_android_dummy.cc
@@ -90,7 +90,5 @@ return 0.0f; } -void VolumeControl::SetPowerSaveMode(bool power_save_on) {} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/cast_media_dummy.cc b/chromecast/media/cma/backend/cast_media_dummy.cc index 0d51f32..f27a180 100644 --- a/chromecast/media/cma/backend/cast_media_dummy.cc +++ b/chromecast/media/cma/backend/cast_media_dummy.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chromecast/media/cma/backend/audio_buildflags.h" #include "chromecast/public/cast_media_shlib.h" #include "chromecast/public/media/media_capabilities_shlib.h" #include "chromecast/public/volume_control.h" @@ -52,6 +53,8 @@ config.codec == kCodecPCM || config.codec == kCodecVorbis; } +#if BUILDFLAG(VOLUME_CONTROL_IN_MEDIA_SHLIB) + void VolumeControl::Initialize(const std::vector<std::string>& argv) {} void VolumeControl::Finalize() {} void VolumeControl::AddVolumeObserver(VolumeObserver* observer) {} @@ -85,5 +88,7 @@ void VolumeControl::SetPowerSaveMode(bool power_save_on) {} +#endif // BUILDFLAG(VOLUME_CONTROL_IN_MEDIA_SHLIB) + } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/desktop/volume_control_desktop.cc b/chromecast/media/cma/backend/desktop/volume_control_desktop.cc index 640a0bd4..a4c505c 100644 --- a/chromecast/media/cma/backend/desktop/volume_control_desktop.cc +++ b/chromecast/media/cma/backend/desktop/volume_control_desktop.cc
@@ -215,8 +215,5 @@ return (db - kMinVolumeDbfs) / (kMaxVolumeDbfs - kMinVolumeDbfs); } -// static -void VolumeControl::SetPowerSaveMode(bool power_save_on) {} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc index 53f7cbb..ac7c6fd6 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
@@ -144,9 +144,11 @@ &MediaPipelineBackendManager::EnterPowerSaveMode); } else if (!had_playing_audio_streams && new_playing_audio_streams > 0) { power_save_timer_.Stop(); - metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( - "Cast.Platform.VolumeControl.PowerSaveOff"); - VolumeControl::SetPowerSaveMode(false); + if (VolumeControl::SetPowerSaveMode) { + metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( + "Cast.Platform.VolumeControl.PowerSaveOff"); + VolumeControl::SetPowerSaveMode(false); + } } if (sfx) { @@ -185,8 +187,7 @@ void MediaPipelineBackendManager::EnterPowerSaveMode() { DCHECK_EQ(TotalPlayingAudioStreamsCount(), 0); - DCHECK(VolumeControl::SetPowerSaveMode); - if (!power_save_enabled_) { + if (!VolumeControl::SetPowerSaveMode || !power_save_enabled_) { return; } metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( @@ -264,7 +265,7 @@ void MediaPipelineBackendManager::SetPowerSaveEnabled(bool power_save_enabled) { MAKE_SURE_MEDIA_THREAD(SetPowerSaveEnabled, power_save_enabled); power_save_enabled_ = power_save_enabled; - if (!power_save_enabled_) { + if (VolumeControl::SetPowerSaveMode && !power_save_enabled_) { VolumeControl::SetPowerSaveMode(false); } }
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/stream_mixer.cc index 7efc0b3..728d790c 100644 --- a/chromecast/media/cma/backend/stream_mixer.cc +++ b/chromecast/media/cma/backend/stream_mixer.cc
@@ -780,6 +780,24 @@ audio_output_redirectors_.erase(redirector); } +void StreamMixer::ModifyAudioOutputRedirection( + AudioOutputRedirector* redirector, + std::vector<std::pair<AudioContentType, std::string>> + stream_match_patterns) { + POST_THROUGH_INPUT_THREAD(&StreamMixer::ModifyAudioOutputRedirectionOnThread, + redirector, std::move(stream_match_patterns)); +} + +void StreamMixer::ModifyAudioOutputRedirectionOnThread( + AudioOutputRedirector* redirector, + std::vector<std::pair<AudioContentType, std::string>> + stream_match_patterns) { + auto it = audio_output_redirectors_.find(redirector); + if (it != audio_output_redirectors_.end()) { + it->second->UpdatePatterns(std::move(stream_match_patterns)); + } +} + void StreamMixer::PostLoopbackData(int64_t expected_playback_time, SampleFormat format, int sample_rate,
diff --git a/chromecast/media/cma/backend/stream_mixer.h b/chromecast/media/cma/backend/stream_mixer.h index 4fe927e..19111ef 100644 --- a/chromecast/media/cma/backend/stream_mixer.h +++ b/chromecast/media/cma/backend/stream_mixer.h
@@ -9,6 +9,7 @@ #include <memory> #include <string> +#include <utility> #include <vector> #include "base/containers/flat_map.h" @@ -100,6 +101,10 @@ void AddAudioOutputRedirector( std::unique_ptr<AudioOutputRedirector> redirector); void RemoveAudioOutputRedirector(AudioOutputRedirector* redirector); + void ModifyAudioOutputRedirection( + AudioOutputRedirector* redirector, + std::vector<std::pair<AudioContentType, std::string>> + stream_match_patterns); // Sets the volume multiplier for the given content |type|. void SetVolume(AudioContentType type, float level); @@ -194,6 +199,10 @@ void AddAudioOutputRedirectorOnThread( std::unique_ptr<AudioOutputRedirector> redirector); void RemoveAudioOutputRedirectorOnThread(AudioOutputRedirector* redirector); + void ModifyAudioOutputRedirectionOnThread( + AudioOutputRedirector* redirector, + std::vector<std::pair<AudioContentType, std::string>> + stream_match_patterns); void PostLoopbackData(int64_t expected_playback_time, SampleFormat sample_format,
diff --git a/chromecast/media/cma/backend/stream_mixer_unittest.cc b/chromecast/media/cma/backend/stream_mixer_unittest.cc index 286b93c..a703af6 100644 --- a/chromecast/media/cma/backend/stream_mixer_unittest.cc +++ b/chromecast/media/cma/backend/stream_mixer_unittest.cc
@@ -385,12 +385,16 @@ } MockRedirectedAudioOutput* AddOutputRedirector( - const AudioOutputRedirectionConfig& config) { + const AudioOutputRedirectionConfig& config, + AudioOutputRedirector** redirector_ptr = nullptr) { auto redirected_output = std::make_unique<MockRedirectedAudioOutput>(kNumChannels); MockRedirectedAudioOutput* redirected_output_ptr = redirected_output.get(); auto redirector = std::make_unique<AudioOutputRedirector>( config, std::move(redirected_output)); + if (redirector_ptr) { + *redirector_ptr = redirector.get(); + } mixer_->AddAudioOutputRedirector(std::move(redirector)); return redirected_output_ptr; } @@ -1332,6 +1336,64 @@ mixer_.reset(); } +TEST_F(StreamMixerTest, ModifyOutputRedirection) { + std::vector<std::unique_ptr<MockMixerSource>> inputs; + inputs.push_back( + std::make_unique<MockMixerSource>(kTestSamplesPerSecond, "matches")); + inputs.push_back( + std::make_unique<MockMixerSource>(kTestSamplesPerSecond, "asdf")); + + for (size_t i = 0; i < inputs.size(); ++i) { + mixer_->AddInput(inputs[i].get()); + } + WaitForMixer(); + mock_output_->ClearData(); + + AudioOutputRedirectionConfig config; + config.stream_match_patterns.push_back({AudioContentType::kMedia, "*match*"}); + AudioOutputRedirector* redirector_ptr = nullptr; + MockRedirectedAudioOutput* redirected_output_ptr = + AddOutputRedirector(config, &redirector_ptr); + CHECK(redirector_ptr); + WaitForMixer(); + + const int kNumFrames = 32; + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->SetData(GetTestData(i)); + } + PlaybackOnce(); + mock_output_->ClearData(); + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->SetData(GetTestData(i)); + } + PlaybackOnce(); + + CheckRedirectorOutput(redirected_output_ptr, {inputs[1].get()}, + {inputs[0].get()}, kNumFrames); + + std::vector<std::pair<AudioContentType, std::string>> new_match_patterns = { + {AudioContentType::kMedia, "*asdf*"}}; + mixer_->ModifyAudioOutputRedirection(redirector_ptr, + std::move(new_match_patterns)); + WaitForMixer(); + mock_output_->ClearData(); + + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->SetData(GetTestData(i)); + } + PlaybackOnce(); + mock_output_->ClearData(); + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->SetData(GetTestData(i)); + } + PlaybackOnce(); + + CheckRedirectorOutput(redirected_output_ptr, {inputs[0].get()}, + {inputs[1].get()}, kNumFrames); + + mixer_.reset(); +} + #if GTEST_HAS_DEATH_TEST using StreamMixerDeathTest = StreamMixerTest;
diff --git a/chromecast/public/avsettings.h b/chromecast/public/avsettings.h index 09e9b30..28c0217 100644 --- a/chromecast/public/avsettings.h +++ b/chromecast/public/avsettings.h
@@ -7,6 +7,10 @@ #include <stdint.h> +#include <string> +#include <vector> + +#include "chromecast_export.h" #include "output_restrictions.h" #include "task_runner.h" @@ -353,6 +357,12 @@ HdrOutputType output_type) = 0; }; +// Entrypoint for overridable AvSettings shared library. +class CHROMECAST_EXPORT AvSettingsShlib { + public: + static AvSettings* Create(const std::vector<std::string>& argv); +}; + } // namespace chromecast #endif // CHROMECAST_PUBLIC_AVSETTINGS_H_
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h index 6255274..6242076 100644 --- a/chromecast/public/cast_media_shlib.h +++ b/chromecast/public/cast_media_shlib.h
@@ -10,9 +10,11 @@ #include <functional> #include <memory> #include <string> +#include <utility> #include <vector> #include "chromecast_export.h" +#include "volume_control.h" namespace chromecast { namespace media { @@ -176,6 +178,12 @@ // AddAudioOutputRedirection(). static void RemoveAudioOutputRedirection(AudioOutputRedirectorToken* token) __attribute__((__weak__)); + + // Updates the set of streams that an audio output redirector should apply to. + static void ModifyAudioOutputRedirection( + AudioOutputRedirectorToken* token, + std::vector<std::pair<AudioContentType, std::string /* device ID */>> + stream_match_patterns) __attribute__((__weak__)); }; } // namespace media
diff --git a/chromecast/public/media/redirected_audio_output.h b/chromecast/public/media/redirected_audio_output.h index 694742ac..15b624e4 100644 --- a/chromecast/public/media/redirected_audio_output.h +++ b/chromecast/public/media/redirected_audio_output.h
@@ -34,7 +34,7 @@ bool apply_volume = false; // Any extra delay to apply to the timestamps sent to the redirected output. - // Note that the dealyed timestamp will be used internally for AV sync. + // Note that the delayed timestamp will be used internally for AV sync. int64_t extra_delay_microseconds = 0; // Patterns to determine which audio streams should be redirected. If a stream
diff --git a/chromecast/public/volume_control.h b/chromecast/public/volume_control.h index 63d4669..042a0b69 100644 --- a/chromecast/public/volume_control.h +++ b/chromecast/public/volume_control.h
@@ -102,7 +102,9 @@ // Called to enable power save mode when no audio is being played // (|power_save_on| will be true in this case), and to disable power save mode // when audio playback resumes (|power_save_on| will be false). - static void SetPowerSaveMode(bool power_save_on); + // NOTE: This is optional (therefore a weak symbol) because most platforms + // do not have any need to implement it. + static void SetPowerSaveMode(bool power_save_on) __attribute__((weak)); // Converts a volume level in the range [0.0, 1.0] to/from a volume in dB. // The volume in dB should be full-scale (so a volume level of 1.0 would be
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc index 28c8a4b..acc0c61 100644 --- a/chromeos/components/drivefs/drivefs_host_unittest.cc +++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -364,7 +364,7 @@ .WillOnce(RunQuitClosure(&quit_closure)); // Eventually we must attempt unmount. EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID", - chromeos::UNMOUNT_OPTIONS_NONE, _)); + chromeos::UNMOUNT_OPTIONS_LAZY, _)); SendOnMounted(); run_loop.Run(); ASSERT_TRUE(host_->IsMounted()); @@ -500,7 +500,7 @@ auto token = StartMount(); DispatchMountSuccessEvent(token); EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID", - chromeos::UNMOUNT_OPTIONS_NONE, _)); + chromeos::UNMOUNT_OPTIONS_LAZY, _)); host_.reset(); EXPECT_FALSE(PendingConnectionManager::Get().OpenIpcChannel(token, {}));
diff --git a/chromeos/components/drivefs/drivefs_session.cc b/chromeos/components/drivefs/drivefs_session.cc index 581cbd8..2de44b8 100644 --- a/chromeos/components/drivefs/drivefs_session.cc +++ b/chromeos/components/drivefs/drivefs_session.cc
@@ -55,7 +55,7 @@ disk_mount_manager_->RemoveObserver(this); if (!mount_path_.empty()) { disk_mount_manager_->UnmountPath(mount_path_.value(), - chromeos::UNMOUNT_OPTIONS_NONE, {}); + chromeos::UNMOUNT_OPTIONS_LAZY, {}); mount_path_.clear(); } }
diff --git a/chromeos/components/drivefs/drivefs_session_unittest.cc b/chromeos/components/drivefs/drivefs_session_unittest.cc index c69d32aa..b7b6906 100644 --- a/chromeos/components/drivefs/drivefs_session_unittest.cc +++ b/chromeos/components/drivefs/drivefs_session_unittest.cc
@@ -76,7 +76,7 @@ chromeos::MOUNT_TYPE_NETWORK_STORAGE, {}}); EXPECT_CALL(disk_manager_, UnmountPath(kExpectedMountPath, - chromeos::UNMOUNT_OPTIONS_NONE, _)); + chromeos::UNMOUNT_OPTIONS_LAZY, _)); mounter.reset(); } @@ -91,7 +91,7 @@ chromeos::MOUNT_TYPE_NETWORK_STORAGE, {}}); EXPECT_CALL(disk_manager_, UnmountPath(kExpectedMountPath, - chromeos::UNMOUNT_OPTIONS_NONE, _)); + chromeos::UNMOUNT_OPTIONS_LAZY, _)); } TEST_F(DriveFsDiskMounterTest, DestroyBeforeMounted) {
diff --git a/chromeos/components/proximity_auth/e2e_test/cros.py b/chromeos/components/proximity_auth/e2e_test/cros.py deleted file mode 100644 index 1209e896..0000000 --- a/chromeos/components/proximity_auth/e2e_test/cros.py +++ /dev/null
@@ -1,584 +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. - -import logging -import os -import subprocess -import sys -import time - -# Add the telemetry directory to Python's search paths. -current_directory = os.path.dirname(os.path.realpath(__file__)) -perf_dir = os.path.realpath( - os.path.join(current_directory, '..', '..', '..', 'tools', 'perf')) -if perf_dir not in sys.path: - sys.path.append(perf_dir) -from chrome_telemetry_build import chromium_config -telemetry_dir = chromium_config.GetTelemetryDir() -if telemetry_dir not in sys.path: - sys.path.append(telemetry_dir) - -from telemetry.internal.browser import browser_options -from telemetry.internal.browser import browser_finder -from telemetry.core import exceptions -from telemetry.core import util -from telemetry.core import cros_interface -from telemetry.internal.browser import extension_to_load - -logger = logging.getLogger('proximity_auth.%s' % __name__) - -class AccountPickerScreen(object): - """ Wrapper for the ChromeOS account picker screen. - - The account picker screen is the WebContents page used for both the lock - screen and signin screen. - - Note: This class assumes the account picker screen only has one user. If there - are multiple user pods, the first one will be used. - """ - - class AuthType: - """ The authentication type expected for a user pod. """ - OFFLINE_PASSWORD = 0 - ONLINE_SIGN_IN = 1 - NUMERIC_PIN = 2 - USER_CLICK = 3 - EXPAND_THEN_USER_CLICK = 4 - FORCE_OFFLINE_PASSWORD = 5 - - class SmartLockState: - """ The state of the Smart Lock icon on a user pod. - """ - NOT_SHOWN = 'not_shown' - AUTHENTICATED = 'authenticated' - LOCKED = 'locked' - HARD_LOCKED = 'hardlocked' - TO_BE_ACTIVATED = 'to_be_activated' - SPINNER = 'spinner' - - # JavaScript expression for getting the user pod on the page - _GET_POD_JS = 'document.getElementById("pod-row").pods[0]' - - def __init__(self, oobe, chromeos): - """ - Args: - oobe: Inspector page of the OOBE WebContents. - chromeos: The parent Chrome wrapper. - """ - self._oobe = oobe - self._chromeos = chromeos - - @property - def is_lockscreen(self): - return self._oobe.EvaluateJavaScript( - '!document.getElementById("sign-out-user-item").hidden') - - @property - def auth_type(self): - return self._oobe.EvaluateJavaScript( - '{{ @pod }}.authType', pod=self._GET_POD_JS) - - @property - def smart_lock_state(self): - icon_shown = self._oobe.EvaluateJavaScript( - '!{{ @pod }}.customIconElement.hidden', pod=self._GET_POD_JS) - if not icon_shown: - return self.SmartLockState.NOT_SHOWN - class_list_dict = self._oobe.EvaluateJavaScript( - '{{ @pod }}.customIconElement.querySelector(".custom-icon").classList', - pod=self._GET_POD_JS) - class_list = [v for k,v in class_list_dict.items() if k != 'length'] - - if 'custom-icon-unlocked' in class_list: - return self.SmartLockState.AUTHENTICATED - if 'custom-icon-locked' in class_list: - return self.SmartLockState.LOCKED - if 'custom-icon-hardlocked' in class_list: - return self.SmartLockState.HARD_LOCKED - if 'custom-icon-locked-to-be-activated' in class_list: - return self.SmartLockState.TO_BE_ACTIVATED - if 'custom-icon-spinner' in class_list: - return self.SmartLockState.SPINNER - - def WaitForSmartLockState(self, state, wait_time_secs=60): - """ Waits for the Smart Lock icon to reach the given state. - - Args: - state: A value in AccountPickerScreen.SmartLockState - wait_time_secs: The time to wait - Returns: - True if the state is reached within the wait time, else False. - """ - try: - util.WaitFor(lambda: self.smart_lock_state == state, wait_time_secs) - return True - except exceptions.TimeoutException: - return False - - def EnterPassword(self): - """ Enters the password to unlock or sign-in. - - Raises: - TimeoutException: entering the password fails to enter/resume the user - session. - """ - assert(self.auth_type == self.AuthType.OFFLINE_PASSWORD or - self.auth_type == self.AuthType.FORCE_OFFLINE_PASSWORD) - oobe = self._oobe - oobe.EvaluateJavaScript( - '{{ @pod }}.passwordElement.value = {{ password }}', - pod=self._GET_POD_JS, password=self._chromeos.password) - oobe.EvaluateJavaScript( - '{{ @pod }}.activate()', pod=self._GET_POD_JS) - util.WaitFor(lambda: (self._chromeos.session_state == - ChromeOS.SessionState.IN_SESSION), - 5) - - def UnlockWithClick(self): - """ Clicks the user pod to unlock or sign-in. """ - assert(self.auth_type == self.AuthType.USER_CLICK) - self._oobe.EvaluateJavaScript( - '{{ @pod }}.activate()', pod=self._GET_POD_JS) - - -class SmartLockSettings(object): - """ Wrapper for the Smart Lock settings in chromeos://settings. - """ - def __init__(self, tab, chromeos): - """ - Args: - tab: Inspector page of the chromeos://settings tag. - chromeos: The parent Chrome wrapper. - """ - self._tab = tab - self._chromeos = chromeos - - @property - def is_smart_lock_enabled(self): - ''' Returns true if the settings show that Smart Lock is enabled. ''' - return self._tab.EvaluateJavaScript( - '!document.getElementById("easy-unlock-enabled").hidden') - - def TurnOffSmartLock(self): - """ Turns off Smart Lock. - - Smart Lock is turned off by clicking the turn-off button and navigating - through the resulting overlay. - - Raises: - TimeoutException: Timed out waiting for Smart Lock to be turned off. - """ - assert(self.is_smart_lock_enabled) - tab = self._tab - tab.EvaluateJavaScript( - 'document.getElementById("easy-unlock-turn-off-button").click()') - tab.WaitForJavaScriptCondition( - '!document.getElementById("easy-unlock-turn-off-overlay").hidden && ' - 'document.getElementById("easy-unlock-turn-off-confirm") != null', - timeout=10) - tab.EvaluateJavaScript( - 'document.getElementById("easy-unlock-turn-off-confirm").click()') - tab.WaitForJavaScriptCondition( - '!document.getElementById("easy-unlock-disabled").hidden', timeout=15) - - def StartSetup(self): - """ Starts the Smart Lock setup flow by clicking the button. - """ - assert(not self.is_smart_lock_enabled) - self._tab.EvaluateJavaScript( - 'document.getElementById("easy-unlock-setup-button").click()') - - def StartSetupAndReturnApp(self): - """ Runs the setup and returns the wrapper to the setup app. - - After clicking the setup button in the settings page, enter the password to - reauthenticate the user before the app launches. - - Returns: - A SmartLockApp object of the app that was launched. - - Raises: - TimeoutException: Timed out waiting for app. - """ - self.StartSetup() - util.WaitFor(lambda: (self._chromeos.session_state == - ChromeOS.SessionState.LOCK_SCREEN), - 5) - lock_screen = self._chromeos.GetAccountPickerScreen() - lock_screen.EnterPassword() - util.WaitFor(lambda: self._chromeos.GetSmartLockApp() is not None, 10) - return self._chromeos.GetSmartLockApp() - - -class SmartLockApp(object): - """ Wrapper for the Smart Lock setup dialog. - - Note: This does not include the app's background page. - """ - - class PairingState: - """ The current state of the setup flow. """ - SCAN = 'scan' - PAIR = 'pair' - CLICK_FOR_TRIAL_RUN = 'click_for_trial_run' - TRIAL_RUN_COMPLETED = 'trial_run_completed' - PROMOTE_SMARTLOCK_FOR_ANDROID = 'promote-smart-lock-for-android' - - def __init__(self, app_page, chromeos): - """ - Args: - app_page: Inspector page of the app window. - chromeos: The parent Chrome wrapper. - """ - self._app_page = app_page - self._chromeos = chromeos - - @property - def pairing_state(self): - ''' Returns the state the app is currently in. - - Raises: - ValueError: The current state is unknown. - ''' - state = self._app_page.EvaluateJavaScript( - 'document.body.getAttribute("step")') - if state == 'scan': - return SmartLockApp.PairingState.SCAN - elif state == 'pair': - return SmartLockApp.PairingState.PAIR - elif state == 'promote-smart-lock-for-android': - return SmartLockApp.PairingState.PROMOTE_SMARTLOCK_FOR_ANDROID - elif state == 'complete': - button_text = self._app_page.EvaluateJavaScript( - 'document.getElementById("pairing-button").textContent') - button_text = button_text.strip().lower() - if button_text == 'try it out': - return SmartLockApp.PairingState.CLICK_FOR_TRIAL_RUN - elif button_text == 'done': - return SmartLockApp.PairingState.TRIAL_RUN_COMPLETED - else: - raise ValueError('Unknown button text: %s', button_text) - else: - raise ValueError('Unknown pairing state: %s' % state) - - def FindPhone(self, retries=3): - """ Starts the initial step to find nearby phones. - - The app must be in the SCAN state. - - Args: - retries: The number of times to retry if no phones are found. - Returns: - True if a phone is found, else False. - """ - assert(self.pairing_state == self.PairingState.SCAN) - for _ in xrange(retries): - self._ClickPairingButton() - if self.pairing_state == self.PairingState.PAIR: - return True - # Wait a few seconds before retrying. - time.sleep(10) - return False - - def PairPhone(self): - """ Starts the step of finding nearby phones. - - The app must be in the PAIR state. - - Returns: - True if pairing succeeded, else False. - """ - assert(self.pairing_state == self.PairingState.PAIR) - self._ClickPairingButton() - if self.pairing_state == self.PairingState.PROMOTE_SMARTLOCK_FOR_ANDROID: - self._ClickPairingButton() - return self.pairing_state == self.PairingState.CLICK_FOR_TRIAL_RUN - - def StartTrialRun(self): - """ Starts the trial run. - - The app must be in the CLICK_FOR_TRIAL_RUN state. - - Raises: - TimeoutException: Timed out starting the trial run. - """ - assert(self.pairing_state == self.PairingState.CLICK_FOR_TRIAL_RUN) - self._app_page.EvaluateJavaScript( - 'document.getElementById("pairing-button").click()') - util.WaitFor(lambda: (self._chromeos.session_state == - ChromeOS.SessionState.LOCK_SCREEN), - 10) - - def DismissApp(self): - """ Dismisses the app after setup is completed. - - The app must be in the TRIAL_RUN_COMPLETED state. - """ - assert(self.pairing_state == self.PairingState.TRIAL_RUN_COMPLETED) - self._app_page.EvaluateJavaScript( - 'document.getElementById("pairing-button").click()') - - def _ClickPairingButton(self): - # Waits are needed because the clicks occur before the button label changes. - time.sleep(1) - self._app_page.EvaluateJavaScript( - 'document.getElementById("pairing-button").click()') - time.sleep(1) - self._app_page.WaitForJavaScriptCondition( - '!document.getElementById("pairing-button").disabled', timeout=60) - time.sleep(1) - self._app_page.WaitForJavaScriptCondition( - '!document.getElementById("pairing-button-title")' - '.classList.contains("animated-fade-out")', timeout=5) - self._app_page.WaitForJavaScriptCondition( - '!document.getElementById("pairing-button-title")' - '.classList.contains("animated-fade-in")', timeout=5) - - -class ChromeOS(object): - """ Wrapper for a remote ChromeOS device. - - Operations performed through this wrapper are sent through the network to - Chrome using the Chrome DevTools API. Therefore, any function may throw an - exception if the communication to the remote device is severed. - """ - - class SessionState: - """ The state of the user session. - """ - SIGNIN_SCREEN = 'signin_screen' - IN_SESSION = 'in_session' - LOCK_SCREEN = 'lock_screen' - - _SMART_LOCK_SETTINGS_URL = 'chrome://settings/search#Smart%20Lock' - - def __init__(self, remote_address, username, password, ssh_port=None): - """ - Args: - remote_address: The remote address of the cros device. - username: The username of the account to test. - password: The password of the account to test. - ssh_port: The ssh port to connect to. - """ - self._remote_address = remote_address - self._username = username - self._password = password - self._ssh_port = ssh_port - self._browser_to_create = None - self._browser = None - self._cros_interface = None - self._background_page = None - self._processes = [] - - @property - def username(self): - ''' Returns the username of the user to login. ''' - return self._username - - @property - def password(self): - ''' Returns the password of the user to login. ''' - return self._password - - @property - def session_state(self): - ''' Returns the state of the user session. ''' - assert(self._browser is not None) - if self._browser.oobe_exists: - if self._cros_interface.IsCryptohomeMounted(self.username, False): - return self.SessionState.LOCK_SCREEN - else: - return self.SessionState.SIGNIN_SCREEN - else: - return self.SessionState.IN_SESSION; - - @property - def cryptauth_access_token(self): - try: - self._background_page.WaitForJavaScriptCondition( - 'var __token = __token || null; ' - 'chrome.identity.getAuthToken(function(token) {' - ' __token = token;' - '}); ' - '__token != null', timeout=5) - return self._background_page.EvaluateJavaScript('__token'); - except exceptions.TimeoutException: - logger.error('Failed to get access token.'); - return '' - - def __enter__(self): - return self - - def __exit__(self, *args): - if self._browser is not None: - self._browser.Close() - if self._browser_to_create is not None: - self._browser_to_create.CleanUpEnvironment() - if self._cros_interface is not None: - self._cros_interface.CloseConnection() - for process in self._processes: - process.terminate() - - def Start(self, local_app_path=None): - """ Connects to the ChromeOS device and logs in. - Args: - local_app_path: A path on the local device containing the Smart Lock app - to use instead of the app on the ChromeOS device. - Return: - |self| for using in a "with" statement. - """ - assert(self._browser is None) - - finder_opts = browser_options.BrowserFinderOptions('cros-chrome') - finder_opts.CreateParser().parse_args(args=[]) - finder_opts.cros_remote = self._remote_address - if self._ssh_port is not None: - finder_opts.cros_remote_ssh_port = self._ssh_port - finder_opts.verbosity = 1 - - browser_opts = finder_opts.browser_options - browser_opts.create_browser_with_oobe = True - browser_opts.disable_component_extensions_with_background_pages = False - browser_opts.gaia_login = True - browser_opts.username = self._username - browser_opts.password = self._password - browser_opts.auto_login = True - - self._cros_interface = cros_interface.CrOSInterface( - finder_opts.cros_remote, - finder_opts.cros_remote_ssh_port, - finder_opts.cros_ssh_identity) - - browser_opts.disable_default_apps = local_app_path is not None - if local_app_path is not None: - easy_unlock_app = extension_to_load.ExtensionToLoad( - path=local_app_path, - browser_type='cros-chrome', - is_component=True) - finder_opts.extensions_to_load.append(easy_unlock_app) - - self._browser_to_create = browser_finder.FindBrowser(finder_opts) - self._browser_to_create.SetUpEnvironment(browser_opts) - - retries = 3 - while self._browser is not None or retries > 0: - try: - self._browser = self._browser_to_create.Create() - break; - except (exceptions.LoginException) as e: - logger.error('Timed out logging in: %s' % e); - if retries == 1: - raise - - bg_page_path = '/_generated_background_page.html' - util.WaitFor( - lambda: self._FindSmartLockAppPage(bg_page_path) is not None, - 10); - self._background_page = self._FindSmartLockAppPage(bg_page_path) - return self - - def GetAccountPickerScreen(self): - """ Returns the wrapper for the lock screen or sign-in screen. - - Return: - An instance of AccountPickerScreen. - Raises: - TimeoutException: Timed out waiting for account picker screen to load. - """ - assert(self._browser is not None) - assert(self.session_state == self.SessionState.LOCK_SCREEN or - self.session_state == self.SessionState.SIGNIN_SCREEN) - oobe = self._browser.oobe - def IsLockScreenResponsive(): - return (oobe.EvaluateJavaScript("typeof Oobe == 'function'") and - oobe.EvaluateJavaScript( - "typeof Oobe.authenticateForTesting == 'function'")) - util.WaitFor(IsLockScreenResponsive, 10) - oobe.WaitForJavaScriptCondition( - 'document.getElementById("pod-row") && ' - 'document.getElementById("pod-row").pods && ' - 'document.getElementById("pod-row").pods.length > 0', timeout=10) - return AccountPickerScreen(oobe, self) - - def GetSmartLockSettings(self): - """ Returns the wrapper for the Smart Lock settings. - A tab will be navigated to chrome://settings if it does not exist. - - Return: - An instance of SmartLockSettings. - Raises: - TimeoutException: Timed out waiting for settings page. - """ - if not len(self._browser.tabs): - self._browser.New() - tab = self._browser.tabs[0] - url = tab.EvaluateJavaScript('document.location.href') - if url != self._SMART_LOCK_SETTINGS_URL: - tab.Navigate(self._SMART_LOCK_SETTINGS_URL) - - # Wait for settings page to be responsive. - tab.WaitForJavaScriptCondition( - 'document.getElementById("easy-unlock-disabled") && ' - 'document.getElementById("easy-unlock-enabled") && ' - '(!document.getElementById("easy-unlock-disabled").hidden || ' - ' !document.getElementById("easy-unlock-enabled").hidden)', - timeout=10) - settings = SmartLockSettings(tab, self) - logger.info('Started Smart Lock settings: enabled=%s' % - settings.is_smart_lock_enabled) - return settings - - def GetSmartLockApp(self): - """ Returns the wrapper for the Smart Lock setup app. - - Return: - An instance of SmartLockApp or None if the app window does not exist. - """ - app_page = self._FindSmartLockAppPage('/pairing.html') - if app_page is not None: - # Wait for app window to be responsive. - tab.WaitForJavaScriptCondition( - 'document.getElementById("pairing-button") != null', timeout=10) - return SmartLockApp(app_page, self) - return None - - def SetCryptAuthStaging(self, cryptauth_staging_url): - logger.info('Setting CryptAuth to Staging') - try: - self._background_page.ExecuteJavaScript(""" - var key = app.CryptAuthClient.GOOGLE_API_URL_OVERRIDE_; - var __complete = false; - chrome.storage.local.set({key: {{ url }}}, function() { - __complete = true; - });""", - url=cryptauth_staging_url) - self._background_page.WaitForJavaScriptCondition( - '__complete == true', timeout=10) - except exceptions.TimeoutException: - logger.error('Failed to override CryptAuth to staging url.') - - def RunBtmon(self): - """ Runs the btmon command. - Return: - A subprocess.Popen object of the btmon process. - """ - assert(self._cros_interface) - cmd = self._cros_interface.FormSSHCommandLine(['btmon']) - process = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - self._processes.append(process) - return process - - def _FindSmartLockAppPage(self, page_name): - try: - extensions = self._browser.extensions.GetByExtensionId( - 'mkaemigholebcgchlkbankmihknojeak') - except KeyError: - return None - for extension_page in extensions: - pathname = extension_page.EvaluateJavaScript( - 'document.location.pathname') - if pathname == page_name: - return extension_page - return None
diff --git a/chromeos/components/proximity_auth/e2e_test/cryptauth.py b/chromeos/components/proximity_auth/e2e_test/cryptauth.py deleted file mode 100644 index 7373fa9..0000000 --- a/chromeos/components/proximity_auth/e2e_test/cryptauth.py +++ /dev/null
@@ -1,140 +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. - -import httplib -import json -import logging -import pprint -import time - -logger = logging.getLogger('proximity_auth.%s' % __name__) - -_GOOGLE_APIS_URL = 'www.googleapis.com' -_REQUEST_PATH = '/cryptauth/v1/%s?alt=JSON' - -class CryptAuthClient(object): - """ A client for making blocking CryptAuth API calls. """ - - def __init__(self, access_token, google_apis_url=_GOOGLE_APIS_URL): - self._access_token = access_token - self._google_apis_url = google_apis_url - - def GetMyDevices(self): - """ Invokes the GetMyDevices API. - - Returns: - A list of devices or None if the API call fails. - Each device is a dictionary of the deserialized JSON returned by - CryptAuth. - """ - request_data = { - 'approvedForUnlockRequired': False, - 'allowStaleRead': False, - 'invocationReason': 13 # REASON_MANUAL - } - response = self._SendRequest('deviceSync/getmydevices', request_data) - return response['devices'] if response is not None else None - - def GetUnlockKey(self): - """ - Returns: - The unlock key registered with CryptAuth if it exists or None. - The device is a dictionary of the deserialized JSON returned by CryptAuth. - """ - devices = self.GetMyDevices() - if devices is None: - return None - - for device in devices: - if device['unlockKey']: - return device - return None - - def ToggleEasyUnlock(self, enable, public_key=''): - """ Calls the ToggleEasyUnlock API. - Args: - enable: True to designate the device specified by |public_key| as an - unlock key. - public_key: The public key of the device to toggle. Ignored if |enable| is - False, which toggles all unlock keys off. - Returns: - True upon success, else False. - """ - request_data = { 'enable': enable, } - if not enable: - request_data['applyToAll'] = True - else: - request_data['publicKey'] = public_key - response = self._SendRequest('deviceSync/toggleeasyunlock', request_data) - return response is not None - - def FindEligibleUnlockDevices(self, time_delta_millis=None): - """ Finds devices eligible to be an unlock key. - Args: - time_delta_millis: If specified, then only return eligible devices that - have contacted CryptAuth in the last time delta. - Returns: - A tuple containing two lists, one of eligible devices and the other of - ineligible devices. - Each device is a dictionary of the deserialized JSON returned by - CryptAuth. - """ - request_data = {} - if time_delta_millis is not None: - request_data['maxLastUpdateTimeDeltaMillis'] = time_delta_millis * 1000; - - response = self._SendRequest( - 'deviceSync/findeligibleunlockdevices', request_data) - if response is None: - return None - eligibleDevices = ( - response['eligibleDevices'] if 'eligibleDevices' in response else []) - ineligibleDevices = ( - response['ineligibleDevices'] if ( - 'ineligibleDevices' in response) else []) - return eligibleDevices, ineligibleDevices - - def PingPhones(self, timeout_secs=10): - """ Asks CryptAuth to ping registered phones and determine their status. - Args: - timeout_secs: The number of seconds to wait for phones to respond. - Returns: - A tuple containing two lists, one of eligible devices and the other of - ineligible devices. - Each device is a dictionary of the deserialized JSON returned by - CryptAuth. - """ - response = self._SendRequest( - 'deviceSync/senddevicesynctickle', - { 'tickleType': 'updateEnrollment' }) - if response is None: - return None - # We wait for phones to update their status with CryptAuth. - logger.info('Waiting for %s seconds for phone status...' % timeout_secs) - time.sleep(timeout_secs) - return self.FindEligibleUnlockDevices(time_delta_millis=timeout_secs) - - def _SendRequest(self, function_path, request_data): - """ Sends an HTTP request to CryptAuth and returns the deserialized - response. - """ - conn = httplib.HTTPSConnection(self._google_apis_url) - path = _REQUEST_PATH % function_path - - headers = { - 'authorization': 'Bearer ' + self._access_token, - 'Content-Type': 'application/json' - } - body = json.dumps(request_data) - logger.info('Making request to %s with body:\n%s' % ( - path, pprint.pformat(request_data))) - conn.request('POST', path, body, headers) - - response = conn.getresponse() - if response.status == 204: - return {} - if response.status != 200: - logger.warning('Request to %s failed: %s' % (path, response.status)) - return None - return json.loads(response.read())
diff --git a/chromeos/components/proximity_auth/e2e_test/setup_test.py b/chromeos/components/proximity_auth/e2e_test/setup_test.py deleted file mode 100644 index 9d7cf785..0000000 --- a/chromeos/components/proximity_auth/e2e_test/setup_test.py +++ /dev/null
@@ -1,167 +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. - -""" Script that exercises the Smart Lock setup flow, testing that a nearby phone -can be found and used to unlock a Chromebook. - -Note: This script does not currently automate Android phones, so make sure that -a phone is properly configured and online before starting the test. - -Usage: - python setup_test.py --remote_address REMOTE_ADDRESS - --username USERNAME - --password PASSWORD - [--app_path APP_PATH] - [--ssh_port SSH_PORT] - [--cryptauth_staging_url STAGING_URL] - If |--app_path| is provided, then a copy of the Smart Lock app on the local - machine will be used instead of the app on the ChromeOS device. -""" - -import argparse -import cros -import cryptauth -import logging -import os -import subprocess -import sys -import tempfile - -logger = logging.getLogger('proximity_auth.%s' % __name__) - -class SmartLockSetupError(Exception): - pass - -def pingable_address(address): - try: - subprocess.check_output(['ping', '-c', '1', '-W', '1', address]) - except subprocess.CalledProcessError: - raise argparse.ArgumentError('%s cannot be reached.' % address) - return address - -def email(arg): - tokens = arg.lower().split('@') - if len(tokens) != 2 or '.' not in tokens[1]: - raise argparse.ArgumentError('%s is not a valid email address' % arg) - name, domain = tokens - if domain == 'gmail.com': - name = name.replace('.', '') - return '@'.join([name, domain]) - -def directory(path): - if not os.path.isdir(path): - raise argparse.ArgumentError('%s is not a directory' % path) - return path - -def ParseArgs(): - parser = argparse.ArgumentParser(prog='python setup_test.py') - parser.add_argument('--remote_address', required=True, type=pingable_address) - parser.add_argument('--username', required=True, type=email) - parser.add_argument('--password', required=True) - parser.add_argument('--ssh_port', type=int) - parser.add_argument('--app_path', type=directory) - parser.add_argument('--cryptauth_staging_url', type=str) - args = parser.parse_args() - return args - -def CheckCryptAuthState(access_token): - cryptauth_client = cryptauth.CryptAuthClient(access_token) - - # Check if we can make CryptAuth requests. - if cryptauth_client.GetMyDevices() is None: - logger.error('Cannot reach CryptAuth on test machine.') - return False - - if cryptauth_client.GetUnlockKey() is not None: - logger.info('Smart Lock currently enabled, turning off on Cryptauth...') - if not cryptauth_client.ToggleEasyUnlock(False): - logger.error('ToggleEasyUnlock request failed.') - return False - - result = cryptauth_client.FindEligibleUnlockDevices() - if result is None: - logger.error('FindEligibleUnlockDevices request failed') - return False - eligibleDevices, _ = result - if len(eligibleDevices) == 0: - logger.warn('No eligible phones found, trying to ping phones...') - result = cryptauth_client.PingPhones() - if result is None or not len(result[0]): - logger.error('Pinging phones failed :(') - return False - else: - logger.info('Pinging phones succeeded!') - else: - logger.info('Found eligible device: %s' % ( - eligibleDevices[0]['friendlyDeviceName'])) - return True - -def _NavigateSetupDialog(chromeos, app): - logger.info('Scanning for nearby phones...') - btmon = chromeos.RunBtmon() - find_phone_success = app.FindPhone() - btmon.terminate() - - if not find_phone_success: - fd, filepath = tempfile.mkstemp(prefix='btmon-') - os.write(fd, btmon.stdout.read()) - os.close(fd) - logger.info('Logs for btmon can be found at %s' % filepath) - raise SmartLockSetupError("Failed to find nearby phone.") - - logger.info('Phone found! Starting pairing...') - if not app.PairPhone(): - raise SmartLockSetupError("Failed to pair with phone.") - logger.info('Pairing success! Starting trial run...') - app.StartTrialRun() - - logger.info('Unlocking for trial run...') - lock_screen = chromeos.GetAccountPickerScreen() - lock_screen.WaitForSmartLockState( - lock_screen.SmartLockState.AUTHENTICATED) - lock_screen.UnlockWithClick() - - logger.info('Trial run success! Dismissing app...') - app.DismissApp() - -def RunSetupTest(args): - logger.info('Starting test for %s at %s' % ( - args.username, args.remote_address)) - if args.app_path is not None: - logger.info('Replacing Smart Lock app with %s' % args.app_path) - - chromeos = cros.ChromeOS( - args.remote_address, args.username, args.password, ssh_port=args.ssh_port) - with chromeos.Start(local_app_path=args.app_path): - logger.info('Chrome initialized') - - # TODO(tengs): The access token is currently fetched from the Smart Lock - # app's background page. To be more robust, we should instead mint the - # access token ourselves. - if not CheckCryptAuthState(chromeos.cryptauth_access_token): - raise SmartLockSetupError('Failed to check CryptAuth state') - - logger.info('Opening Smart Lock settings...') - settings = chromeos.GetSmartLockSettings() - assert(not settings.is_smart_lock_enabled) - - if args.cryptauth_staging_url is not None: - chromeos.SetCryptAuthStaging(args.cryptauth_staging_url) - - logger.info('Starting Smart Lock setup flow...') - app = settings.StartSetupAndReturnApp() - - if app is None: - raise SmartLockSetupError('Failed to obtain set up app window') - - _NavigateSetupDialog(chromeos, app) - -def main(): - logging.basicConfig() - logging.getLogger('proximity_auth').setLevel(logging.INFO) - args = ParseArgs() - RunSetupTest(args) - -if __name__ == '__main__': - main()
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_result.cc b/chromeos/services/device_sync/cryptauth_enrollment_result.cc index dfcc7f9f..0c85864 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_result.cc +++ b/chromeos/services/device_sync/cryptauth_enrollment_result.cc
@@ -116,7 +116,11 @@ stream << "[Error: KeyActions do not specify an active key]"; break; case ResultCode::kErrorKeyCreationKeyTypeNotSupported: - stream << "[Error: KeyCreation instructions specify unsupported KeyType]"; + stream << "[Error: Key-creation instructions specify unsupported " + << "KeyType]"; + break; + case ResultCode::kErrorUserKeyPairCreationInstructionsInvalid: + stream << "[Error: Key-creation instructions for user key pair invalid]"; break; case ResultCode::kErrorSymmetricKeyCreationMissingServerDiffieHellman: stream << "[Error: Cannot create symmetric key; missing server "
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_result.h b/chromeos/services/device_sync/cryptauth_enrollment_result.h index f093af12..0213753 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_result.h +++ b/chromeos/services/device_sync/cryptauth_enrollment_result.h
@@ -79,6 +79,9 @@ kErrorKeyActionsDoNotSpecifyAnActiveKey, // KeyCreation instructions specify an unsupported KeyType. kErrorKeyCreationKeyTypeNotSupported, + // Invalid key-creation instructions for user key pair. It must be P256 and + // active. + kErrorUserKeyPairCreationInstructionsInvalid, // Cannot create a symmetric key without the server's Diffie-Hellman key. kErrorSymmetricKeyCreationMissingServerDiffieHellman, // Failed to compute at least one key proof.
diff --git a/chromeos/services/device_sync/cryptauth_key_bundle.cc b/chromeos/services/device_sync/cryptauth_key_bundle.cc index 62f0ac1..d37c762 100644 --- a/chromeos/services/device_sync/cryptauth_key_bundle.cc +++ b/chromeos/services/device_sync/cryptauth_key_bundle.cc
@@ -152,8 +152,12 @@ } void CryptAuthKeyBundle::AddKey(const CryptAuthKey& key) { + DCHECK(name_ != Name::kUserKeyPair || + key.handle() == kCryptAuthFixedUserKeyPairHandle); + if (key.status() == CryptAuthKey::Status::kActive) DeactivateKeys(); + handle_to_key_map_.insert_or_assign(key.handle(), key); }
diff --git a/chromeos/services/device_sync/cryptauth_key_bundle.h b/chromeos/services/device_sync/cryptauth_key_bundle.h index 296d2b5..cff51ee 100644 --- a/chromeos/services/device_sync/cryptauth_key_bundle.h +++ b/chromeos/services/device_sync/cryptauth_key_bundle.h
@@ -66,6 +66,8 @@ // If the key being added is active, all other keys in the bundle will be // deactivated. If the handle of the input key matches one in the bundle, the // existing key will be overwritten. + // Note: All keys added to the bundle kUserKeyPair must have the handle + // kCryptAuthFixedUserKeyPairHandle. void AddKey(const CryptAuthKey& key); // Activates the key corresponding to |handle| in the bundle and deactivates
diff --git a/chromeos/services/device_sync/cryptauth_key_bundle_unittest.cc b/chromeos/services/device_sync/cryptauth_key_bundle_unittest.cc index 4d27af8..3b0af62b 100644 --- a/chromeos/services/device_sync/cryptauth_key_bundle_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_key_bundle_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chromeos/services/device_sync/cryptauth_key_bundle.h" +#include "chromeos/services/device_sync/cryptauth_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { @@ -20,14 +21,14 @@ } // namespace TEST(DeviceSyncCryptAuthKeyBundleTest, CreateKeyBundle) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); - EXPECT_EQ(bundle.name(), CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); + EXPECT_EQ(bundle.name(), CryptAuthKeyBundle::Name::kLegacyMasterKey); EXPECT_TRUE(bundle.handle_to_key_map().empty()); EXPECT_FALSE(bundle.key_directive()); } TEST(DeviceSyncCryptAuthKeyBundleTest, SetKeyDirective) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); cryptauthv2::KeyDirective key_directive; bundle.set_key_directive(key_directive); ASSERT_TRUE(bundle.key_directive()); @@ -36,20 +37,35 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, AddKey) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); - CryptAuthKey key(kFakeSymmetricKey, CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); - bundle.AddKey(key); - EXPECT_TRUE(bundle.handle_to_key_map().size() == 1); + CryptAuthKeyBundle bundle_legacy(CryptAuthKeyBundle::Name::kLegacyMasterKey); + CryptAuthKey sym_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); + bundle_legacy.AddKey(sym_key); + EXPECT_TRUE(bundle_legacy.handle_to_key_map().size() == 1); + const auto& legacy_it = + bundle_legacy.handle_to_key_map().find(kFakeSymmetricKeyHandle); + ASSERT_TRUE(legacy_it != bundle_legacy.handle_to_key_map().end()); + EXPECT_EQ(legacy_it->first, sym_key.handle()); + EXPECT_EQ(legacy_it->second, sym_key); - const auto& it = bundle.handle_to_key_map().find(kFakeSymmetricKeyHandle); - ASSERT_TRUE(it != bundle.handle_to_key_map().end()); - EXPECT_EQ(it->first, key.handle()); - EXPECT_EQ(it->second, key); + // Note: Handles for kUserKeyPair must be kCryptAuthFixedUserKeyPairHandle. + CryptAuthKeyBundle bundle_user_key_pair( + CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKey asym_key( + kFakePublicKey, kFakePrivateKey, CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, kCryptAuthFixedUserKeyPairHandle); + bundle_user_key_pair.AddKey(asym_key); + EXPECT_TRUE(bundle_user_key_pair.handle_to_key_map().size() == 1); + const auto& user_key_pair_it = bundle_user_key_pair.handle_to_key_map().find( + kCryptAuthFixedUserKeyPairHandle); + ASSERT_TRUE(user_key_pair_it != + bundle_user_key_pair.handle_to_key_map().end()); + EXPECT_EQ(user_key_pair_it->first, asym_key.handle()); + EXPECT_EQ(user_key_pair_it->second, asym_key); } TEST(DeviceSyncCryptAuthKeyBundleTest, AddKey_Inactive) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -72,7 +88,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, AddKey_ActiveKeyDeactivatesOthers) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -95,7 +111,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, AddKey_ReplaceKeyWithSameHandle) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, "same-handle"); bundle.AddKey(symmetric_key); @@ -111,7 +127,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, GetActiveKey_DoesNotExist) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); EXPECT_FALSE(bundle.GetActiveKey()); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, @@ -122,7 +138,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, GetActiveKey_Exists) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -137,7 +153,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, SetActiveKey_InactiveToActive) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -159,7 +175,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, SetActiveKey_ActiveToActive) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -181,7 +197,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, DeactivateKeys) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -203,7 +219,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, DeleteKey) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); @@ -215,7 +231,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, ToAndFromDictionary_Trivial) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); base::Optional<CryptAuthKeyBundle> bundle_from_dict = CryptAuthKeyBundle::FromDictionary(bundle.AsDictionary()); ASSERT_TRUE(bundle_from_dict); @@ -223,7 +239,7 @@ } TEST(DeviceSyncCryptAuthKeyBundleTest, ToAndFromDictionary) { - CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle bundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle);
diff --git a/chromeos/services/device_sync/cryptauth_key_creator.cc b/chromeos/services/device_sync/cryptauth_key_creator.cc index 30c70ce..2716f5a 100644 --- a/chromeos/services/device_sync/cryptauth_key_creator.cc +++ b/chromeos/services/device_sync/cryptauth_key_creator.cc
@@ -14,6 +14,22 @@ base::Optional<std::string> handle) : status(status), type(type), handle(handle) {} +CryptAuthKeyCreator::CreateKeyData::CreateKeyData( + CryptAuthKey::Status status, + cryptauthv2::KeyType type, + const std::string& handle, + const std::string& public_key, + const std::string& private_key) + : status(status), + type(type), + handle(handle), + public_key(public_key), + private_key(private_key) { + DCHECK(!handle.empty()); + DCHECK(!public_key.empty()); + DCHECK(!private_key.empty()); +} + CryptAuthKeyCreator::CreateKeyData::~CreateKeyData() = default; CryptAuthKeyCreator::CreateKeyData::CreateKeyData(const CreateKeyData&) =
diff --git a/chromeos/services/device_sync/cryptauth_key_creator.h b/chromeos/services/device_sync/cryptauth_key_creator.h index 243868d..d0ec0072 100644 --- a/chromeos/services/device_sync/cryptauth_key_creator.h +++ b/chromeos/services/device_sync/cryptauth_key_creator.h
@@ -38,7 +38,7 @@ // the CryptAuth server. Specifically, // // |derived_key| = -// Hkdf(|secret|, salt="CryptAuth Enrollment", info=|derived_key_handle|). +// Hkdf(|secret|, salt="CryptAuth Enrollment", info=|key_bundle_name|). // // The CryptAuth server's Diffie-Hellman key is passed into CreateKeys(), // CreateKeys() generates the client side of the Diffie-Hellman handshake, and @@ -49,12 +49,27 @@ CreateKeyData(CryptAuthKey::Status status, cryptauthv2::KeyType type, base::Optional<std::string> handle = base::nullopt); + + // Special constructor needed to handle existing user key pair. The input + // strings cannot be empty. + CreateKeyData(CryptAuthKey::Status status, + cryptauthv2::KeyType type, + const std::string& handle, + const std::string& public_key, + const std::string& private_key); + ~CreateKeyData(); CreateKeyData(const CreateKeyData&); CryptAuthKey::Status status; cryptauthv2::KeyType type; base::Optional<std::string> handle; + // Special data needed to handle existing user key pair. If these are both + // non-empty strings and the key type is asymmetric, then the key creator + // will bypass the standard key creation and simply return + // CryptAuthKey(|public_key|, |private_key|, |status|, |type|, |handle|). + base::Optional<std::string> public_key; + base::Optional<std::string> private_key; }; CryptAuthKeyCreator();
diff --git a/chromeos/services/device_sync/cryptauth_key_creator_impl.cc b/chromeos/services/device_sync/cryptauth_key_creator_impl.cc index c12f83a..1298e9c 100644 --- a/chromeos/services/device_sync/cryptauth_key_creator_impl.cc +++ b/chromeos/services/device_sync/cryptauth_key_creator_impl.cc
@@ -4,24 +4,14 @@ #include "chromeos/services/device_sync/cryptauth_key_creator_impl.h" -#include <memory> -#include <string> -#include <utility> - -#include "base/base64.h" #include "base/bind.h" -#include "base/containers/flat_map.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" -#include "base/optional.h" #include "base/strings/string_util.h" -#include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/components/multidevice/secure_message_delegate_impl.h" #include "chromeos/services/device_sync/cryptauth_constants.h" -#include "chromeos/services/device_sync/cryptauth_key.h" #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" #include "crypto/hkdf.h" -#include "crypto/random.h" namespace chromeos { @@ -65,17 +55,6 @@ } } -// Creates a handle by base64-encoding 32 random bytes. -std::string CreateRandomHandle() { - std::string bytes(32, '\0'); - crypto::RandBytes(base::WriteInto(&bytes, bytes.size()), bytes.size()); - - std::string handle; - base::Base64Encode(bytes, &handle); - - return handle; -} - } // namespace // static @@ -116,9 +95,10 @@ DCHECK(!keys_to_create.empty()); // Fail if CreateKeys() has already been called. - DCHECK(keys_to_create_.empty() && new_keys_.empty() && + DCHECK(num_keys_to_create_ == 0 && new_keys_.empty() && !create_keys_callback_); + num_keys_to_create_ = keys_to_create.size(); keys_to_create_ = keys_to_create; server_ephemeral_dh_ = server_ephemeral_dh; create_keys_callback_ = std::move(create_keys_callback); @@ -165,29 +145,39 @@ void CryptAuthKeyCreatorImpl::StartKeyCreation() { for (const auto& key_to_create : keys_to_create_) { + const CryptAuthKeyBundle::Name& bundle_name = key_to_create.first; + const CreateKeyData& key_data = key_to_create.second; + // If the key to create is symmetric, derive a symmetric key from the // Diffie-Hellman handshake secrect using HKDF. The CryptAuth v2 // Enrollment protocol specifies that the salt should be "CryptAuth // Enrollment" and the info should be the key handle. This process is // synchronous, unlike SecureMessageDelegate calls. - if (IsValidSymmetricKeyType(key_to_create.second.type)) { - std::string handle = key_to_create.second.handle.has_value() - ? *key_to_create.second.handle - : CreateRandomHandle(); + if (IsValidSymmetricKeyType(key_data.type)) { std::string derived_symmetric_key_material = crypto::HkdfSha256( dh_handshake_secret_->symmetric_key(), - kCryptAuthSymmetricKeyDerivationSalt, handle, - NumBytesForSymmetricKeyType(key_to_create.second.type)); + kCryptAuthSymmetricKeyDerivationSalt, + CryptAuthKeyBundle::KeyBundleNameEnumToString(bundle_name), + NumBytesForSymmetricKeyType(key_data.type)); - OnSymmetricKeyDerived(key_to_create.first, derived_symmetric_key_material, - handle); - } else { - DCHECK(IsValidAsymmetricKeyType(key_to_create.second.type)); + OnSymmetricKeyDerived(bundle_name, derived_symmetric_key_material); - secure_message_delegate_->GenerateKeyPair( - base::Bind(&CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated, - base::Unretained(this), key_to_create.first)); + continue; } + + DCHECK(IsValidAsymmetricKeyType(key_data.type)); + + // If the key material was explicitly set in CreateKeyData, bypass the + // standard key creation. + if (key_data.public_key && key_data.private_key) { + OnAsymmetricKeyPairGenerated(bundle_name, *key_data.public_key, + *key_data.private_key); + continue; + } + + secure_message_delegate_->GenerateKeyPair( + base::Bind(&CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated, + base::Unretained(this), key_to_create.first)); } } @@ -195,7 +185,7 @@ CryptAuthKeyBundle::Name bundle_name, const std::string& public_key, const std::string& private_key) { - DCHECK(keys_to_create_.size() > 0); + DCHECK(num_keys_to_create_ > 0); DCHECK(!public_key.empty() && !private_key.empty()); const CryptAuthKeyCreator::CreateKeyData& create_key_data = @@ -205,26 +195,25 @@ create_key_data.status, create_key_data.type, create_key_data.handle); - keys_to_create_.erase(bundle_name); - if (keys_to_create_.empty()) + --num_keys_to_create_; + if (num_keys_to_create_ == 0) std::move(create_keys_callback_).Run(new_keys_, client_ephemeral_dh_); } void CryptAuthKeyCreatorImpl::OnSymmetricKeyDerived( CryptAuthKeyBundle::Name bundle_name, - const std::string& symmetric_key, - const std::string& handle) { - DCHECK(keys_to_create_.size() > 0); + const std::string& symmetric_key) { + DCHECK(num_keys_to_create_ > 0); DCHECK(!symmetric_key.empty()); const CryptAuthKeyCreator::CreateKeyData& create_key_data = keys_to_create_.find(bundle_name)->second; new_keys_.try_emplace(bundle_name, symmetric_key, create_key_data.status, - create_key_data.type, handle); + create_key_data.type, create_key_data.handle); - keys_to_create_.erase(bundle_name); - if (keys_to_create_.empty()) + --num_keys_to_create_; + if (num_keys_to_create_ == 0) std::move(create_keys_callback_).Run(new_keys_, client_ephemeral_dh_); }
diff --git a/chromeos/services/device_sync/cryptauth_key_creator_impl.h b/chromeos/services/device_sync/cryptauth_key_creator_impl.h index 17eb0a5..8f263b7 100644 --- a/chromeos/services/device_sync/cryptauth_key_creator_impl.h +++ b/chromeos/services/device_sync/cryptauth_key_creator_impl.h
@@ -5,8 +5,6 @@ #ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_ #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_ -#include "chromeos/services/device_sync/cryptauth_key_creator.h" - #include <memory> #include <string> #include <utility> @@ -18,6 +16,7 @@ #include "base/optional.h" #include "chromeos/services/device_sync/cryptauth_key.h" #include "chromeos/services/device_sync/cryptauth_key_bundle.h" +#include "chromeos/services/device_sync/cryptauth_key_creator.h" namespace chromeos { @@ -60,9 +59,9 @@ const std::string& public_key, const std::string& private_key); void OnSymmetricKeyDerived(CryptAuthKeyBundle::Name bundle_name, - const std::string& symmetric_key, - const std::string& handle); + const std::string& symmetric_key); + size_t num_keys_to_create_ = 0; base::flat_map<CryptAuthKeyBundle::Name, CreateKeyData> keys_to_create_; base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey> new_keys_; base::Optional<CryptAuthKey> server_ephemeral_dh_;
diff --git a/chromeos/services/device_sync/cryptauth_key_creator_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_key_creator_impl_unittest.cc index c22eea1..ab35c46 100644 --- a/chromeos/services/device_sync/cryptauth_key_creator_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_key_creator_impl_unittest.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/services/device_sync/cryptauth_key_creator_impl.h" - #include <memory> #include <string> #include <utility> @@ -18,6 +16,7 @@ #include "chromeos/services/device_sync/cryptauth_key.h" #include "chromeos/services/device_sync/cryptauth_key_bundle.h" #include "chromeos/services/device_sync/cryptauth_key_creator.h" +#include "chromeos/services/device_sync/cryptauth_key_creator_impl.h" #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" #include "crypto/hkdf.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,15 +32,19 @@ const char kFakeAsymmetricKeyHandle[] = "asymmetric_key_handle"; const char kFakePublicKeyMaterial[] = "public_key"; const char kFakeSymmetricKeyHandle[] = "symmetric_key_handle"; +const char kFakeProvidedPublicKeyMaterial[] = "provided_public_key"; +const char kFakeProvidedPrivateKeyMaterial[] = "provided_private_key"; -void VerifyCreatedKeysCallback( - const base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey>& - expected_new_keys, - const base::Optional<CryptAuthKey>& expected_client_ephemeral_dh, - const base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey>& new_keys, - const base::Optional<CryptAuthKey>& client_ephemeral_dh) { - EXPECT_EQ(expected_client_ephemeral_dh, client_ephemeral_dh); - EXPECT_EQ(expected_new_keys, new_keys); +size_t NumBytesForSymmetricKeyType(cryptauthv2::KeyType key_type) { + switch (key_type) { + case cryptauthv2::KeyType::RAW128: + return 16u; + case cryptauthv2::KeyType::RAW256: + return 32u; + default: + NOTREACHED(); + return 0u; + } } class FakeSecureMessageDelegateFactory @@ -71,12 +74,19 @@ class DeviceSyncCryptAuthKeyCreatorImplTest : public testing::Test { protected: - DeviceSyncCryptAuthKeyCreatorImplTest() = default; + DeviceSyncCryptAuthKeyCreatorImplTest() + : fake_secure_message_delegate_factory_( + std::make_unique<FakeSecureMessageDelegateFactory>()), + fake_server_ephemeral_dh_(CryptAuthKey( + kFakeServerEphemeralDhPublicKeyMaterial, + fake_secure_message_delegate()->GetPrivateKeyForPublicKey( + kFakeServerEphemeralDhPublicKeyMaterial), + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256)) {} + ~DeviceSyncCryptAuthKeyCreatorImplTest() override = default; void SetUp() override { - fake_secure_message_delegate_factory_ = - std::make_unique<FakeSecureMessageDelegateFactory>(); multidevice::SecureMessageDelegateImpl::Factory::SetInstanceForTesting( fake_secure_message_delegate_factory_.get()); @@ -88,31 +98,81 @@ nullptr); } - CryptAuthKey DeriveSecret( - const base::Optional<CryptAuthKey>& server_ephemeral_dh, - const base::Optional<CryptAuthKey>& client_ephemeral_dh) { + void CallCreateKeys( + const base::flat_map<CryptAuthKeyBundle::Name, + CryptAuthKeyCreator::CreateKeyData>& keys_to_create, + const base::Optional<CryptAuthKey>& server_ephemeral_dh) { + key_creator_->CreateKeys( + keys_to_create, server_ephemeral_dh, + base::BindOnce(&DeviceSyncCryptAuthKeyCreatorImplTest::OnKeysCreated, + base::Unretained(this))); + } + + void VerifyKeyCreation( + const base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey>& + expected_new_keys, + const base::Optional<CryptAuthKey>& expected_client_ephemeral_dh) { + EXPECT_TRUE(new_keys_); + EXPECT_TRUE(client_ephemeral_dh_); + EXPECT_EQ(expected_new_keys, *new_keys_); + EXPECT_EQ(expected_client_ephemeral_dh, *client_ephemeral_dh_); + } + + std::string DeriveSecret(const CryptAuthKey& server_ephemeral_dh, + const CryptAuthKey& client_ephemeral_dh) { std::string derived_key; fake_secure_message_delegate()->DeriveKey( - client_ephemeral_dh->private_key(), server_ephemeral_dh->public_key(), + client_ephemeral_dh.private_key(), server_ephemeral_dh.public_key(), base::Bind([](std::string* derived_key, const std::string& key) { *derived_key = key; }, &derived_key)); - return CryptAuthKey(derived_key, CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::RAW256); + return derived_key; } - CryptAuthKeyCreator* key_creator() { return key_creator_.get(); } + CryptAuthKey DeriveSymmetricKey( + const CryptAuthKeyBundle::Name& bundle_name, + const CryptAuthKeyCreator::CreateKeyData& key_to_create, + const CryptAuthKey& client_ephemeral_dh) { + std::string expected_handshake_secret = + DeriveSecret(fake_server_ephemeral_dh_, client_ephemeral_dh); + + std::string expected_symmetric_key_material = crypto::HkdfSha256( + expected_handshake_secret, kCryptAuthSymmetricKeyDerivationSalt, + CryptAuthKeyBundle::KeyBundleNameEnumToString(bundle_name), + NumBytesForSymmetricKeyType(key_to_create.type)); + + return CryptAuthKey(expected_symmetric_key_material, key_to_create.status, + key_to_create.type, key_to_create.handle); + } multidevice::FakeSecureMessageDelegate* fake_secure_message_delegate() { return fake_secure_message_delegate_factory_->instance(); } + const CryptAuthKey& fake_server_ephemeral_dh() { + return fake_server_ephemeral_dh_; + } + private: + void OnKeysCreated( + const base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey>& new_keys, + const base::Optional<CryptAuthKey>& client_ephemeral_dh) { + new_keys_ = new_keys; + client_ephemeral_dh_ = client_ephemeral_dh; + } + std::unique_ptr<FakeSecureMessageDelegateFactory> fake_secure_message_delegate_factory_; - std::unique_ptr<CryptAuthKeyCreator> key_creator_; + CryptAuthKey fake_server_ephemeral_dh_; + + // A null value (for the outermost Optional) indicates that OnKeysCreated() + // was not called. + base::Optional<base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey>> + new_keys_; + base::Optional<base::Optional<CryptAuthKey>> client_ephemeral_dh_; + DISALLOW_COPY_AND_ASSIGN(DeviceSyncCryptAuthKeyCreatorImplTest); }; @@ -136,53 +196,82 @@ fake_secure_message_delegate()->set_next_public_key(kFakePublicKeyMaterial); - key_creator()->CreateKeys( - keys_to_create, base::nullopt /* fake_server_ephemeral_dh */, - base::BindOnce(VerifyCreatedKeysCallback, expected_new_keys, - base::nullopt /* expected_client_ephemeral_dh */)); + CallCreateKeys(keys_to_create, base::nullopt /* fake_server_ephemeral_dh */); + VerifyKeyCreation(expected_new_keys, + base::nullopt /* expected_client_ephemeral_dh */); } TEST_F(DeviceSyncCryptAuthKeyCreatorImplTest, SymmetricKeyCreation) { + CryptAuthKeyCreator::CreateKeyData symmetric_key_to_create( + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, + kFakeSymmetricKeyHandle); + base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKeyCreator::CreateKeyData> - keys_to_create = { - {CryptAuthKeyBundle::Name::kUserKeyPair, - CryptAuthKeyCreator::CreateKeyData(CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::RAW256, - kFakeSymmetricKeyHandle)}}; + keys_to_create = {{CryptAuthKeyBundle::Name::kLegacyMasterKey, + symmetric_key_to_create}}; - base::Optional<CryptAuthKey> fake_server_ephemeral_dh = - CryptAuthKey(kFakeServerEphemeralDhPublicKeyMaterial, - fake_secure_message_delegate()->GetPrivateKeyForPublicKey( - kFakeServerEphemeralDhPublicKeyMaterial), - CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256); + CryptAuthKey expected_client_ephemeral_dh( + kFakeClientEphemeralDhPublicKeyMaterial, + fake_secure_message_delegate()->GetPrivateKeyForPublicKey( + kFakeClientEphemeralDhPublicKeyMaterial), + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256); - base::Optional<CryptAuthKey> expected_client_ephemeral_dh = - CryptAuthKey(kFakeClientEphemeralDhPublicKeyMaterial, - fake_secure_message_delegate()->GetPrivateKeyForPublicKey( - kFakeClientEphemeralDhPublicKeyMaterial), - CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256); - - CryptAuthKey expected_handshake_secret = - DeriveSecret(fake_server_ephemeral_dh, expected_client_ephemeral_dh); - std::string expected_symmetric_key_material = - crypto::HkdfSha256(expected_handshake_secret.symmetric_key(), - kCryptAuthSymmetricKeyDerivationSalt, - kFakeSymmetricKeyHandle, 32u /* derived_key_size */); - - CryptAuthKey expected_symmetric_key( - expected_symmetric_key_material, CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::RAW256, kFakeSymmetricKeyHandle); + CryptAuthKey expected_symmetric_key = + DeriveSymmetricKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, + symmetric_key_to_create, expected_client_ephemeral_dh); base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey> expected_new_keys = { - {CryptAuthKeyBundle::Name::kUserKeyPair, expected_symmetric_key}}; + {CryptAuthKeyBundle::Name::kLegacyMasterKey, expected_symmetric_key}}; fake_secure_message_delegate()->set_next_public_key( kFakeClientEphemeralDhPublicKeyMaterial); - key_creator()->CreateKeys( - keys_to_create, fake_server_ephemeral_dh, - base::BindOnce(VerifyCreatedKeysCallback, expected_new_keys, - expected_client_ephemeral_dh)); + CallCreateKeys(keys_to_create, fake_server_ephemeral_dh()); + VerifyKeyCreation(expected_new_keys, expected_client_ephemeral_dh); +} + +TEST_F(DeviceSyncCryptAuthKeyCreatorImplTest, + MultipleKeyCreation_KeyMaterialProvidedForAsymmetricKey) { + CryptAuthKeyCreator::CreateKeyData symmetric_key_to_create( + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, + kFakeSymmetricKeyHandle); + + base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKeyCreator::CreateKeyData> + keys_to_create = { + {CryptAuthKeyBundle::Name::kUserKeyPair, + CryptAuthKeyCreator::CreateKeyData( + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, + kFakeAsymmetricKeyHandle, kFakeProvidedPublicKeyMaterial, + kFakeProvidedPrivateKeyMaterial)}, + {CryptAuthKeyBundle::Name::kLegacyMasterKey, + symmetric_key_to_create}}; + + CryptAuthKey expected_client_ephemeral_dh( + kFakeClientEphemeralDhPublicKeyMaterial, + fake_secure_message_delegate()->GetPrivateKeyForPublicKey( + kFakeClientEphemeralDhPublicKeyMaterial), + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256); + + CryptAuthKey expected_asymmetric_key( + kFakeProvidedPublicKeyMaterial, kFakeProvidedPrivateKeyMaterial, + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, + kFakeAsymmetricKeyHandle); + + CryptAuthKey expected_symmetric_key = + DeriveSymmetricKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, + symmetric_key_to_create, expected_client_ephemeral_dh); + + base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey> expected_new_keys = { + {CryptAuthKeyBundle::Name::kUserKeyPair, expected_asymmetric_key}, + {CryptAuthKeyBundle::Name::kLegacyMasterKey, expected_symmetric_key}}; + + // There is no need to generate an asymmetric key for kUserKeyPair since we + // passed in the key material to CreateKeyData. + fake_secure_message_delegate()->set_next_public_key( + kFakeClientEphemeralDhPublicKeyMaterial); + + CallCreateKeys(keys_to_create, fake_server_ephemeral_dh()); + VerifyKeyCreation(expected_new_keys, expected_client_ephemeral_dh); } } // namespace device_sync
diff --git a/chromeos/services/device_sync/cryptauth_key_proof_computer.h b/chromeos/services/device_sync/cryptauth_key_proof_computer.h index 456570a0e..c389783 100644 --- a/chromeos/services/device_sync/cryptauth_key_proof_computer.h +++ b/chromeos/services/device_sync/cryptauth_key_proof_computer.h
@@ -25,7 +25,7 @@ // Symmetric keys: The HMAC-SHA256 of the payload, using a key derived from // the input symmetric key. Schematically, // -// HMAC(HKDF(|symmetric_key|, |salt|, info=|key_handle|), |payload|) +// HMAC(HKDF(|symmetric_key|, |salt|, |info|), |payload|) // // Asymmetric keys: A DER-encoded ECDSA signature (RFC 3279) of the // concatenation of the salt and payload strings. @@ -33,10 +33,12 @@ // // Sign(|private_key|, |salt| + |payload|) // -// The CryptAuth v2 Enrollment protocol states that the -// SyncKeysResponse::random_session_id, sent by the CryptAuth server, be used as -// the payload for key proofs. In the future, key crossproofs might be employed, -// where the payload will consist of other key proofs. +// Specifically, the CryptAuth v2 Enrollment protocol states that +// 1) |payload| = SyncKeysResponse::random_session_id, +// 2) |salt| = "CryptAuth Key Proof", +// 3) |info| = key bundle name (needed for symmetric keys only). +// In the future, key crossproofs might be employed, where the payload will +// consist of other key proofs. // // Requirements: // - Currently, the only supported key types are RAW128 and RAW256 for @@ -47,10 +49,13 @@ virtual ~CryptAuthKeyProofComputer() = default; // Returns null if key proof computation failed. + // Note: The parameter |info| must be non-null for symmetric keys, but it is + // not used for asymmetric keys. virtual base::Optional<std::string> ComputeKeyProof( const CryptAuthKey& key, const std::string& payload, - const std::string& salt) = 0; + const std::string& salt, + const base::Optional<std::string>& info) = 0; DISALLOW_COPY_AND_ASSIGN(CryptAuthKeyProofComputer); };
diff --git a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.cc b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.cc index 275a9219..d3f81e7 100644 --- a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.cc +++ b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.cc
@@ -83,21 +83,24 @@ base::Optional<std::string> CryptAuthKeyProofComputerImpl::ComputeKeyProof( const CryptAuthKey& key, const std::string& payload, - const std::string& salt) { - if (key.IsSymmetricKey()) - return ComputeSymmetricKeyProof(key, payload, salt); + const std::string& salt, + const base::Optional<std::string>& info) { + if (key.IsAsymmetricKey()) + return ComputeAsymmetricKeyProof(key, payload, salt); - return ComputeAsymmetricKeyProof(key, payload, salt); + DCHECK(info); + return ComputeSymmetricKeyProof(key, payload, salt, *info); } base::Optional<std::string> CryptAuthKeyProofComputerImpl::ComputeSymmetricKeyProof( const CryptAuthKey& symmetric_key, const std::string& payload, - const std::string& salt) { - std::string derived_symmetric_key_material = crypto::HkdfSha256( - symmetric_key.symmetric_key(), salt, symmetric_key.handle(), - NumBytesForSymmetricKeyType(symmetric_key.type())); + const std::string& salt, + const std::string& info) { + std::string derived_symmetric_key_material = + crypto::HkdfSha256(symmetric_key.symmetric_key(), salt, info, + NumBytesForSymmetricKeyType(symmetric_key.type())); crypto::HMAC hmac(crypto::HMAC::HashAlgorithm::SHA256); std::vector<unsigned char> signed_payload(hmac.DigestLength());
diff --git a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.h b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.h index 710b0f62..1ed9afd 100644 --- a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.h +++ b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl.h
@@ -34,9 +34,11 @@ ~CryptAuthKeyProofComputerImpl() override; // CryptAuthKeyProofComputer: - base::Optional<std::string> ComputeKeyProof(const CryptAuthKey& key, - const std::string& payload, - const std::string& salt) override; + base::Optional<std::string> ComputeKeyProof( + const CryptAuthKey& key, + const std::string& payload, + const std::string& salt, + const base::Optional<std::string>& info) override; private: CryptAuthKeyProofComputerImpl(); @@ -44,7 +46,8 @@ base::Optional<std::string> ComputeSymmetricKeyProof( const CryptAuthKey& symmetric_key, const std::string& payload, - const std::string& salt); + const std::string& salt, + const std::string& info); base::Optional<std::string> ComputeAsymmetricKeyProof( const CryptAuthKey& asymmetric_key, const std::string& payload,
diff --git a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl_unittest.cc index 02519a6..59e9dd8 100644 --- a/chromeos/services/device_sync/cryptauth_key_proof_computer_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_key_proof_computer_impl_unittest.cc
@@ -107,7 +107,8 @@ base::Optional<std::string> key_proof = CryptAuthKeyProofComputerImpl::Factory::Get() ->BuildInstance() - ->ComputeKeyProof(key, kTestPayload, kAsymmetricTestSalt); + ->ComputeKeyProof(key, kTestPayload, kAsymmetricTestSalt, + base::nullopt /* info */); EXPECT_TRUE(key_proof); // Verify the key proof which should be of the form: @@ -126,18 +127,19 @@ TEST(DeviceSyncCryptAuthKeyProofComputerImplTest, Symmetric256KeyProofComputation_Success) { CryptAuthKey key(ByteVectorToString(kTestSymmetricKeyBytes), - CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, - ByteVectorToString(kSymmetricTestInfoBytes)); + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256); base::Optional<std::string> key_proof = CryptAuthKeyProofComputerImpl::Factory::Get() ->BuildInstance() ->ComputeKeyProof(key, kTestPayload, - ByteVectorToString(kSymmetricTestSaltBytes)); + ByteVectorToString(kSymmetricTestSaltBytes), + ByteVectorToString(kSymmetricTestInfoBytes)); + EXPECT_TRUE(key_proof); // Verify the key proof which should be of the form: - // HMAC(HKDF(|key|, |salt|, info=<key handle>), |payload|) + // HMAC(HKDF(|key|, |salt|, |info|), |payload|) crypto::HMAC hmac(crypto::HMAC::HashAlgorithm::SHA256); EXPECT_TRUE( hmac.Init(ByteVectorToString(kExpectedDerivedSymmetricKey32Bytes))); @@ -147,14 +149,14 @@ TEST(DeviceSyncCryptAuthKeyProofComputerImplTest, Symmetric128KeyProofComputation_Success) { CryptAuthKey key(ByteVectorToString(kTestSymmetricKeyBytes), - CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW128, - ByteVectorToString(kSymmetricTestInfoBytes)); + CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW128); base::Optional<std::string> key_proof = CryptAuthKeyProofComputerImpl::Factory::Get() ->BuildInstance() ->ComputeKeyProof(key, kTestPayload, - ByteVectorToString(kSymmetricTestSaltBytes)); + ByteVectorToString(kSymmetricTestSaltBytes), + ByteVectorToString(kSymmetricTestInfoBytes)); EXPECT_TRUE(key_proof); crypto::HMAC hmac(crypto::HMAC::HashAlgorithm::SHA256); @@ -171,7 +173,8 @@ base::Optional<std::string> key_proof = CryptAuthKeyProofComputerImpl::Factory::Get() ->BuildInstance() - ->ComputeKeyProof(key, kTestPayload, kAsymmetricTestSalt); + ->ComputeKeyProof(key, kTestPayload, kAsymmetricTestSalt, + base::nullopt /* info */); EXPECT_FALSE(key_proof); }
diff --git a/chromeos/services/device_sync/cryptauth_key_registry.h b/chromeos/services/device_sync/cryptauth_key_registry.h index ee05b3f6..c8f83a9 100644 --- a/chromeos/services/device_sync/cryptauth_key_registry.h +++ b/chromeos/services/device_sync/cryptauth_key_registry.h
@@ -37,6 +37,8 @@ // Adds |key| to the key bundle with |name|. If the key being added is active, // all other keys in the bundle will be deactivated. If the handle of the // input key matches one in the bundle, the existing key will be overwritten. + // Note: All keys added to the bundle kUserKeyPair must have the handle + // kCryptAuthFixedUserKeyPairHandle. virtual void AddEnrolledKey(CryptAuthKeyBundle::Name name, const CryptAuthKey& key);
diff --git a/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc index 5bfa752..45efd13 100644 --- a/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc
@@ -5,6 +5,7 @@ #include "chromeos/services/device_sync/cryptauth_key_registry_impl.h" #include "base/stl_util.h" +#include "chromeos/services/device_sync/cryptauth_constants.h" #include "chromeos/services/device_sync/pref_names.h" #include "components/prefs/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" @@ -48,11 +49,11 @@ TEST_F(DeviceSyncCryptAuthKeyRegistryImplTest, GetActiveKey_NoActiveKey) { CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, "sym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); EXPECT_FALSE( - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair)); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey)); } TEST_F(DeviceSyncCryptAuthKeyRegistryImplTest, GetActiveKey) { @@ -61,13 +62,13 @@ CryptAuthKey asym_key("public-key", "private-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, "asym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, asym_key); const CryptAuthKey* key = - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(key); EXPECT_EQ(asym_key, *key); } @@ -75,18 +76,19 @@ TEST_F(DeviceSyncCryptAuthKeyRegistryImplTest, AddKey) { CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::RAW256, "sym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); const CryptAuthKeyBundle* key_bundle = - key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(key_bundle); const CryptAuthKey* active_key = - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(active_key); EXPECT_EQ(sym_key, *active_key); - CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle expected_bundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle.AddKey(sym_key); EXPECT_EQ(expected_bundle, *key_bundle); @@ -100,14 +102,14 @@ CryptAuthKey asym_key("public-key", "private-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, "asym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, asym_key); expected_bundle.AddKey(asym_key); EXPECT_EQ(expected_bundle, *key_bundle); active_key = - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(active_key); EXPECT_EQ(asym_key, *active_key); @@ -123,22 +125,23 @@ CryptAuthKey asym_key("public-key", "private-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, "asym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, asym_key); - key_registry()->SetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->SetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, "sym-handle"); const CryptAuthKey* key = - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey); EXPECT_TRUE(key); sym_key.set_status(CryptAuthKey::Status::kActive); EXPECT_EQ(sym_key, *key); - CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle expected_bundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle.AddKey(sym_key); asym_key.set_status(CryptAuthKey::Status::kInactive); expected_bundle.AddKey(asym_key); @@ -155,17 +158,18 @@ CryptAuthKey asym_key("public-key", "private-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, "asym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, asym_key); - key_registry()->DeactivateKeys(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->DeactivateKeys(CryptAuthKeyBundle::Name::kLegacyMasterKey); EXPECT_FALSE( - key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair)); + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kLegacyMasterKey)); - CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle expected_bundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle.AddKey(sym_key); asym_key.set_status(CryptAuthKey::Status::kInactive); expected_bundle.AddKey(asym_key); @@ -182,16 +186,16 @@ CryptAuthKey asym_key("public-key", "private-key", CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256, "asym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, asym_key); - key_registry()->DeleteKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->DeleteKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, "sym-handle"); const CryptAuthKeyBundle* key_bundle = - key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(key_bundle); EXPECT_FALSE( @@ -199,7 +203,8 @@ EXPECT_TRUE( base::ContainsKey(key_bundle->handle_to_key_map(), "asym-handle")); - CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle expected_bundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle.AddKey(asym_key); base::Value expected_dict(base::Value::Type::DICTIONARY); expected_dict.SetKey( @@ -211,23 +216,24 @@ TEST_F(DeviceSyncCryptAuthKeyRegistryImplTest, SetKeyDirective) { CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, cryptauthv2::KeyType::RAW256, "sym-handle"); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, sym_key); cryptauthv2::KeyDirective key_directive; key_directive.set_enroll_time_millis(1000); - key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kLegacyMasterKey, key_directive); const CryptAuthKeyBundle* key_bundle = - key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair); + key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); ASSERT_TRUE(key_bundle); EXPECT_TRUE(key_bundle->key_directive()); EXPECT_EQ(key_directive.SerializeAsString(), key_bundle->key_directive()->SerializeAsString()); - CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + CryptAuthKeyBundle expected_bundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle.AddKey(sym_key); expected_bundle.set_key_directive(key_directive); base::Value expected_dict(base::Value::Type::DICTIONARY); @@ -239,18 +245,19 @@ TEST_F(DeviceSyncCryptAuthKeyRegistryImplTest, ConstructorPopulatesBundlesUsingPref) { - CryptAuthKey asym_key("public-key", "private", CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::P256, "asym-handle"); - CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kActive, - cryptauthv2::KeyType::RAW256, "sym-handle"); + CryptAuthKey asym_key( + "public-key", "private-key", CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, kCryptAuthFixedUserKeyPairHandle); key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, asym_key); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, - sym_key); + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::RAW256, "sym-handle"); cryptauthv2::KeyDirective key_directive; key_directive.set_enroll_time_millis(1000); - key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, + sym_key); + key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kLegacyMasterKey, key_directive); // A new registry using the same pref service that was just written. @@ -262,19 +269,18 @@ const CryptAuthKeyBundle* key_bundle_user_key_pair = key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair); ASSERT_TRUE(key_bundle_user_key_pair); - - const CryptAuthKeyBundle* key_bundle_legacy_master_key = - key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); - CryptAuthKeyBundle expected_bundle_user_key_pair( CryptAuthKeyBundle::Name::kUserKeyPair); expected_bundle_user_key_pair.AddKey(asym_key); - expected_bundle_user_key_pair.set_key_directive(key_directive); EXPECT_EQ(expected_bundle_user_key_pair, *key_bundle_user_key_pair); + const CryptAuthKeyBundle* key_bundle_legacy_master_key = + key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kLegacyMasterKey); + ASSERT_TRUE(key_bundle_legacy_master_key); CryptAuthKeyBundle expected_bundle_legacy_master_key( CryptAuthKeyBundle::Name::kLegacyMasterKey); expected_bundle_legacy_master_key.AddKey(sym_key); + expected_bundle_legacy_master_key.set_key_directive(key_directive); EXPECT_EQ(expected_bundle_legacy_master_key, *key_bundle_legacy_master_key); }
diff --git a/chromeos/services/device_sync/cryptauth_v2_enroller_impl.cc b/chromeos/services/device_sync/cryptauth_v2_enroller_impl.cc index 4b812da..a55688d 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enroller_impl.cc +++ b/chromeos/services/device_sync/cryptauth_v2_enroller_impl.cc
@@ -254,48 +254,59 @@ key_type == cryptauthv2::KeyType::P256; } +// The key bundle kUserKeyPair has special standing in order to 1) accommodate +// any existing key from v1 Enrollment and 2) enforce that the key is not +// rotated. As such, only one user key pair should exist in the key bundle, and +// it should be an active, P-256 key with handle +// kCryptAuthFixedUserKeyPairHandle. +// +// It is possible that CryptAuth could request the creation of a new user key +// pair even if the client sends information about an existing key in the +// SyncKeysRequest. If this happens, the client should re-use the existing user +// key pair key material when creating a new key. At the end of the enrollment +// flow, the existing key will be replaced with this new key that has the same +// public/private keys. +// // Returns an error code if the key-creation instructions are invalid and null // otherwise. base::Optional<CryptAuthEnrollmentResult::ResultCode> -ProcessKeyCreationInstructions( - const CryptAuthKeyBundle::Name& bundle_name, - const SyncSingleKeyResponse& single_key_response, - const std::string& server_ephemeral_dh, - base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create, - base::Optional<cryptauthv2::KeyDirective>* new_key_directive) { - if (single_key_response.key_creation() == SyncSingleKeyResponse::NONE) +ProcessNewUserKeyPairInstructions( + CryptAuthKey::Status status, + cryptauthv2::KeyType type, + const CryptAuthKey* current_active_key, + base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create) { + if (type != cryptauthv2::KeyType::P256) { + PA_LOG(ERROR) << "User key pair must have KeyType P256."; + return CryptAuthEnrollmentResult::ResultCode:: + kErrorUserKeyPairCreationInstructionsInvalid; + } + + // Because no more than one user key pair can exist in the bundle, the newly + // created key must be active. + if (status != CryptAuthKey::Status::kActive) { + PA_LOG(ERROR) << "New user key pair must be active."; + return CryptAuthEnrollmentResult::ResultCode:: + kErrorUserKeyPairCreationInstructionsInvalid; + } + + // If a user key pair already exists in the registry, reuse the same key data. + if (current_active_key && current_active_key->IsAsymmetricKey() && + !current_active_key->private_key().empty()) { + PA_LOG(WARNING) << "Received request to create new user key pair while one " + << "already exists in the key registry. Reusing existing " + << "key material."; + + *new_key_to_create = CryptAuthKeyCreator::CreateKeyData( + status, type, kCryptAuthFixedUserKeyPairHandle, + current_active_key->public_key(), current_active_key->private_key()); + return base::nullopt; - - if (!IsSupportedKeyType(single_key_response.key_type())) { - PA_LOG(ERROR) << "KeyType " << single_key_response.key_type() << " " - << "not supported."; - return CryptAuthEnrollmentResult::ResultCode:: - kErrorKeyCreationKeyTypeNotSupported; } - // Symmetric keys cannot be created without the server's Diffie-Hellman key. - if (server_ephemeral_dh.empty() && - (single_key_response.key_type() == cryptauthv2::KeyType::RAW128 || - single_key_response.key_type() == cryptauthv2::KeyType::RAW256)) { - PA_LOG(ERROR) - << "Missing server's Diffie-Hellman key. Cannot create symmetric keys."; - return CryptAuthEnrollmentResult::ResultCode:: - kErrorSymmetricKeyCreationMissingServerDiffieHellman; - } - - // CryptAuth demands that the key in the kUserKeyPair bundle has a fixed - // handle name. For other key bundles, do not specify a handle name; let - // CryptAuthKey generate a handle for us. - base::Optional<std::string> new_key_handle; - if (bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair) - new_key_handle = kCryptAuthFixedUserKeyPairHandle; - + // If there is no user key pair in the registry, then the user has never + // successfully enrolled via v1 or v2 Enrollment. Generate a new key pair. *new_key_to_create = CryptAuthKeyCreator::CreateKeyData( - ConvertKeyCreationToKeyStatus(single_key_response.key_creation()), - single_key_response.key_type(), new_key_handle); - - if (single_key_response.has_key_directive()) - *new_key_directive = single_key_response.key_directive(); + status, type, kCryptAuthFixedUserKeyPairHandle); return base::nullopt; } @@ -620,6 +631,51 @@ return error_code; } +base::Optional<CryptAuthEnrollmentResult::ResultCode> +CryptAuthV2EnrollerImpl::ProcessKeyCreationInstructions( + const CryptAuthKeyBundle::Name& bundle_name, + const SyncSingleKeyResponse& single_key_response, + const std::string& server_ephemeral_dh, + base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create, + base::Optional<cryptauthv2::KeyDirective>* new_key_directive) { + if (single_key_response.key_creation() == SyncSingleKeyResponse::NONE) + return base::nullopt; + + CryptAuthKey::Status status = + ConvertKeyCreationToKeyStatus(single_key_response.key_creation()); + cryptauthv2::KeyType type = single_key_response.key_type(); + + if (!IsSupportedKeyType(type)) { + PA_LOG(ERROR) << "KeyType " << type << " not supported."; + return CryptAuthEnrollmentResult::ResultCode:: + kErrorKeyCreationKeyTypeNotSupported; + } + + // Symmetric keys cannot be created without the server's Diffie-Hellman key. + if (server_ephemeral_dh.empty() && (type == cryptauthv2::KeyType::RAW128 || + type == cryptauthv2::KeyType::RAW256)) { + PA_LOG(ERROR) + << "Missing server's Diffie-Hellman key. Cannot create symmetric keys."; + return CryptAuthEnrollmentResult::ResultCode:: + kErrorSymmetricKeyCreationMissingServerDiffieHellman; + } + + if (single_key_response.has_key_directive()) + *new_key_directive = single_key_response.key_directive(); + + // Handle the user key pair special case separately below. + if (bundle_name != CryptAuthKeyBundle::Name::kUserKeyPair) { + *new_key_to_create = CryptAuthKeyCreator::CreateKeyData(status, type); + + return base::nullopt; + } + + DCHECK(bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair); + return ProcessNewUserKeyPairInstructions( + status, type, key_registry_->GetActiveKey(bundle_name), + new_key_to_create); +} + void CryptAuthV2EnrollerImpl::OnSyncKeysFailure(NetworkRequestError error) { FinishAttempt(SyncKeysNetworkRequestErrorToResultCode(error)); } @@ -645,10 +701,12 @@ const CryptAuthKeyBundle::Name& bundle_name = name_key_pair.first; const CryptAuthKey& new_key = name_key_pair.second; + std::string bundle_name_str = + CryptAuthKeyBundle::KeyBundleNameEnumToString(bundle_name); + EnrollSingleKeyRequest* single_key_request = request.add_enroll_single_key_requests(); - single_key_request->set_key_name( - CryptAuthKeyBundle::KeyBundleNameEnumToString(bundle_name)); + single_key_request->set_key_name(bundle_name_str); single_key_request->set_new_key_handle(new_key.handle()); if (new_key.IsAsymmetricKey()) single_key_request->set_key_material(new_key.public_key()); @@ -657,7 +715,7 @@ // SyncKeysResponse as the payload and the particular salt specified by the // v2 Enrollment protocol. base::Optional<std::string> key_proof = key_proof_computer->ComputeKeyProof( - new_key, session_id, kCryptAuthKeyProofSalt); + new_key, session_id, kCryptAuthKeyProofSalt, bundle_name_str); if (!key_proof || key_proof->empty()) { FinishAttempt(CryptAuthEnrollmentResult::ResultCode:: kErrorKeyProofComputationFailed);
diff --git a/chromeos/services/device_sync/cryptauth_v2_enroller_impl.h b/chromeos/services/device_sync/cryptauth_v2_enroller_impl.h index 5b3e01b..ba8012fd 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enroller_impl.h +++ b/chromeos/services/device_sync/cryptauth_v2_enroller_impl.h
@@ -120,6 +120,17 @@ base::flat_map<CryptAuthKeyBundle::Name, cryptauthv2::KeyDirective>* new_key_directives); + // A function to help ProcessSingleKeyResponse() handle the key-creation + // instructions. + base::Optional<CryptAuthEnrollmentResult::ResultCode> + ProcessKeyCreationInstructions( + const CryptAuthKeyBundle::Name& bundle_name, + const cryptauthv2::SyncKeysResponse::SyncSingleKeyResponse& + single_key_response, + const std::string& server_ephemeral_dh, + base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create, + base::Optional<cryptauthv2::KeyDirective>* new_key_directive); + void OnSyncKeysFailure(NetworkRequestError error); void OnKeysCreated(
diff --git a/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc index 26948b4..816c73b 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc
@@ -75,21 +75,13 @@ const char kOldActivePublicKey[] = "old_active_public_key"; const char kOldActivePrivateKey[] = "old_active_private_key"; -const char kOldActiveAsymmetricKeyHandle[] = "old_active_handle"; + +// User key pair active handle must be kCryptAuthFixedUserKeyPairHandle. const CryptAuthKey kOldActiveAsymmetricKey(kOldActivePublicKey, kOldActivePrivateKey, CryptAuthKey::Status::kActive, KeyType::P256, - kOldActiveAsymmetricKeyHandle); - -const char kOldInactivePublicKey[] = "old_inactive_public_key"; -const char kOldInactivePrivateKey[] = "old_inactive_private_key"; -const char kOldInactiveAsymmetricKeyHandle[] = "old_inactive_handle"; -const CryptAuthKey kOldInactiveAsymmetricKey(kOldInactivePublicKey, - kOldInactivePrivateKey, - CryptAuthKey::Status::kInactive, - KeyType::P256, - kOldInactiveAsymmetricKeyHandle); + kCryptAuthFixedUserKeyPairHandle); const char kOldActiveSymmetricKeyMaterial[] = "old_active_symmetric_key"; const char kOldActiveSymmetricKeyHandle[] = "old_active_symmetric_key_handle"; @@ -108,7 +100,6 @@ const char kNewPublicKey[] = "new_public_key"; const char kNewPrivateKey[] = "new_private_key"; -const char kFixedUserKeyPairHandle[] = "device_key"; const char kNewSymmetricKey[] = "new_symmetric_key"; const char kNewSymmetricKeyHandle[] = "new_symmetric_key_handle"; @@ -504,8 +495,26 @@ EXPECT_EQ(key.status(), create_key_data.status); EXPECT_EQ(key.type(), create_key_data.type); - if (bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair) + + // Special handling for user key pair. + if (bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair) { EXPECT_EQ(key.handle(), create_key_data.handle); + const CryptAuthKey* current_active_user_key_pair = + key_registry()->GetActiveKey( + CryptAuthKeyBundle::Name::kUserKeyPair); + if (current_active_user_key_pair) { + EXPECT_EQ(key.public_key(), create_key_data.public_key); + EXPECT_EQ(current_active_user_key_pair->public_key(), + create_key_data.public_key); + + EXPECT_EQ(key.private_key(), create_key_data.private_key); + EXPECT_EQ(current_active_user_key_pair->private_key(), + create_key_data.private_key); + + EXPECT_EQ(KeyType::P256, create_key_data.type); + EXPECT_EQ(CryptAuthKey::Status::kActive, create_key_data.status); + } + } } ASSERT_TRUE(key_creator()->server_ephemeral_dh()->IsAsymmetricKey()); @@ -514,6 +523,31 @@ EXPECT_EQ(KeyType::P256, key_creator()->server_ephemeral_dh()->type()); } + void VerifyEnrollSingleKeyRequest(const CryptAuthKeyBundle::Name& bundle_name, + const CryptAuthKey& new_key) { + const EnrollSingleKeyRequest& single_request_user_key_pair = + enroll_keys_request()->enroll_single_key_requests( + GetKeyBundleIndex(bundle_name)); + + std::string bundle_name_str = + CryptAuthKeyBundle::KeyBundleNameEnumToString(bundle_name); + + EXPECT_EQ(bundle_name_str, single_request_user_key_pair.key_name()); + + EXPECT_EQ(new_key.handle(), single_request_user_key_pair.new_key_handle()); + + // No private or symmetric keys should be sent to CryptAuth, so key_material + // should only ever be populated with a public key. + EXPECT_EQ(new_key.IsAsymmetricKey() ? new_key.public_key() : std::string(), + single_request_user_key_pair.key_material()); + + EXPECT_EQ(CryptAuthKeyProofComputerImpl::Factory::Get() + ->BuildInstance() + ->ComputeKeyProof(new_key, kRandomSessionId, + kCryptAuthKeyProofSalt, bundle_name_str), + single_request_user_key_pair.key_proof()); + } + CryptAuthV2Enroller* enroller() { return enroller_.get(); } CryptAuthKeyRegistry* key_registry() { return key_registry_.get(); } @@ -577,8 +611,6 @@ // Seed key registry. key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, kOldActiveAsymmetricKey); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, - kOldInactiveAsymmetricKey); key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, GetSampleOldKeyDirective()); CryptAuthKeyBundle expected_key_bundle_user_key_pair( @@ -601,29 +633,27 @@ ClientDirective expected_new_client_directive = GetSampleNewClientDirective(); KeyDirective expected_new_key_directive = GetSampleNewKeyDirective(); - // For kUserKeyPair: + // For kUserKeyPair (special case): + // - active --> temporarily active during key creation + // - new --> same handle so overwrites active key with same material + // For kMasterLegacyKey: // - active --> deleted // - inactive --> temporarily active during key creation // - new --> active after created - // For kMasterLegacyKey: - // - active --> active - // - inactive --> inactive - // - new --> inactive std::vector<SyncSingleKeyResponseData> sync_single_key_responses_data = { SyncSingleKeyResponseData( CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), - {{kOldActiveAsymmetricKeyHandle, SyncSingleKeyResponse::DELETE}, - {kOldInactiveAsymmetricKeyHandle, + {{kCryptAuthFixedUserKeyPairHandle, SyncSingleKeyResponse::ACTIVATE}} /* handle_to_action_map */, SyncSingleKeyResponse::ACTIVE /* new_key_creation */, KeyType::P256 /* new_key_type */, expected_new_key_directive /* new_key_directive */), SyncSingleKeyResponseData( CryptAuthKeyBundle::Name::kLegacyMasterKey, key_registry(), - {{kOldActiveSymmetricKeyHandle, SyncSingleKeyResponse::ACTIVATE}, + {{kOldActiveSymmetricKeyHandle, SyncSingleKeyResponse::DELETE}, {kOldInactiveSymmetricKeyHandle, - SyncSingleKeyResponse::DEACTIVATE}} /* handle_to_action_map */, - SyncSingleKeyResponse::INACTIVE /* new_key_creation */, + SyncSingleKeyResponse::ACTIVATE}} /* handle_to_action_map */, + SyncSingleKeyResponse::ACTIVE /* new_key_creation */, KeyType::RAW256 /* new_key_type */, expected_new_key_directive /* new_key_directive */)}; @@ -635,25 +665,30 @@ SendSyncKeysResponse(sync_keys_response); // Verify that the key actions were applied. (Note: New keys not created yet.) - expected_key_bundle_user_key_pair.DeleteKey(kOldActiveAsymmetricKeyHandle); - expected_key_bundle_user_key_pair.SetActiveKey( - kOldInactiveAsymmetricKeyHandle); + // No key actions expected for kUserKeyPair. EXPECT_EQ( expected_key_bundle_user_key_pair, *key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair)); + // In kLegacyMasterKey bundle, former active key should have been deleted and + // former inactive key should now be active. + expected_key_bundle_legacy_master_key.DeleteKey(kOldActiveSymmetricKeyHandle); + expected_key_bundle_legacy_master_key.SetActiveKey( + kOldInactiveSymmetricKeyHandle); EXPECT_EQ(expected_key_bundle_legacy_master_key, *key_registry()->GetKeyBundle( CryptAuthKeyBundle::Name::kLegacyMasterKey)); // Verify the key creation data, and assume successful key creation. + // Note: Since an active user key pair already exists, the same key material + // should re-used. base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey> expected_new_keys = { {CryptAuthKeyBundle::Name::kUserKeyPair, - CryptAuthKey(kNewPublicKey, kNewPrivateKey, + CryptAuthKey(kOldActivePublicKey, kOldActivePrivateKey, CryptAuthKey::Status::kActive, KeyType::P256, - kFixedUserKeyPairHandle)}, + kCryptAuthFixedUserKeyPairHandle)}, {CryptAuthKeyBundle::Name::kLegacyMasterKey, - CryptAuthKey(kNewSymmetricKey, CryptAuthKey::Status::kInactive, + CryptAuthKey(kNewSymmetricKey, CryptAuthKey::Status::kActive, KeyType::RAW256, kNewSymmetricKeyHandle)}}; VerifyKeyCreatorInputs( @@ -666,40 +701,13 @@ EXPECT_EQ(kRandomSessionId, enroll_keys_request()->random_session_id()); EXPECT_EQ(kClientDhPublicKey, enroll_keys_request()->client_ephemeral_dh()); EXPECT_EQ(2, enroll_keys_request()->enroll_single_key_requests_size()); - - std::unique_ptr<CryptAuthKeyProofComputer> key_proof_computer = - CryptAuthKeyProofComputerImpl::Factory::Get()->BuildInstance(); - - const EnrollSingleKeyRequest& single_request_user_key_pair = - enroll_keys_request()->enroll_single_key_requests( - GetKeyBundleIndex(CryptAuthKeyBundle::Name::kUserKeyPair)); - EXPECT_EQ(CryptAuthKeyBundle::KeyBundleNameEnumToString( - CryptAuthKeyBundle::Name::kUserKeyPair), - single_request_user_key_pair.key_name()); - EXPECT_EQ(kFixedUserKeyPairHandle, - single_request_user_key_pair.new_key_handle()); - EXPECT_EQ(kNewPublicKey, single_request_user_key_pair.key_material()); - EXPECT_EQ(key_proof_computer->ComputeKeyProof( - expected_new_keys.find(CryptAuthKeyBundle::Name::kUserKeyPair) - ->second, - kRandomSessionId, kCryptAuthKeyProofSalt), - single_request_user_key_pair.key_proof()); - - const EnrollSingleKeyRequest& single_request_legacy_master_key = - enroll_keys_request()->enroll_single_key_requests( - GetKeyBundleIndex(CryptAuthKeyBundle::Name::kLegacyMasterKey)); - EXPECT_EQ(CryptAuthKeyBundle::KeyBundleNameEnumToString( - CryptAuthKeyBundle::Name::kLegacyMasterKey), - single_request_legacy_master_key.key_name()); - EXPECT_EQ(kNewSymmetricKeyHandle, - single_request_legacy_master_key.new_key_handle()); - EXPECT_TRUE(single_request_legacy_master_key.key_material().empty()); - EXPECT_EQ( - key_proof_computer->ComputeKeyProof( - expected_new_keys.find(CryptAuthKeyBundle::Name::kLegacyMasterKey) - ->second, - kRandomSessionId, kCryptAuthKeyProofSalt), - single_request_legacy_master_key.key_proof()); + VerifyEnrollSingleKeyRequest( + CryptAuthKeyBundle::Name::kUserKeyPair, + expected_new_keys.find(CryptAuthKeyBundle::Name::kUserKeyPair)->second); + VerifyEnrollSingleKeyRequest( + CryptAuthKeyBundle::Name::kLegacyMasterKey, + expected_new_keys.find(CryptAuthKeyBundle::Name::kLegacyMasterKey) + ->second); // Assume a successful EnrollKeys() call. // Note: No parameters in EnrollKeysResponse are processed by the enroller @@ -732,15 +740,70 @@ } TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, - SuccessfulEnrollment_NoKeysCreated) { - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, - kOldActiveAsymmetricKey); - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, - kOldInactiveAsymmetricKey); - key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, - GetSampleOldKeyDirective()); + SuccessfulEnrollment_CreateUserKeyPair_NoKeyInRegistry) { + CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), + GetSamplePreviousClientDirectivePolicyReference()); + + ClientDirective expected_new_client_directive = GetSampleNewClientDirective(); + KeyDirective expected_new_key_directive = GetSampleNewKeyDirective(); + + SyncKeysResponse sync_keys_response = BuildSyncKeysResponse( + {SyncSingleKeyResponseData( + CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), + {} /* handle_to_action_map */, + SyncSingleKeyResponse::ACTIVE /* new_key_creation */, + KeyType::P256 /* new_key_type */, + expected_new_key_directive /* new_key_directive */)}, + kRandomSessionId, kServerEphemeralDh, expected_new_client_directive); + + SendSyncKeysResponse(sync_keys_response); + + // Note: Because there is not an existing kUserKeyPair key in registry, a new + // key should be generated. (If there was an existing key, its key material + // would be reused because the kUserKeyPair key should not be rotated.) + base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKey> expected_new_keys = { + {CryptAuthKeyBundle::Name::kUserKeyPair, + CryptAuthKey(kNewPublicKey, kNewPrivateKey, + CryptAuthKey::Status::kActive, KeyType::P256, + kCryptAuthFixedUserKeyPairHandle)}}; + + VerifyKeyCreatorInputs( + expected_new_keys, + kServerEphemeralDh /* expected_server_ephemeral_dh_public_key */); + + RunKeyCreator(expected_new_keys, kClientEphemeralDh); + + EXPECT_EQ(1, enroll_keys_request()->enroll_single_key_requests_size()); + VerifyEnrollSingleKeyRequest( + CryptAuthKeyBundle::Name::kUserKeyPair, + expected_new_keys.find(CryptAuthKeyBundle::Name::kUserKeyPair)->second); + + SendEnrollKeysResponse(EnrollKeysResponse()); + + EXPECT_EQ(CryptAuthEnrollmentResult( + CryptAuthEnrollmentResult::ResultCode::kSuccessNewKeysEnrolled, + expected_new_client_directive), + enrollment_result()); + CryptAuthKeyBundle expected_key_bundle( - *key_registry()->GetKeyBundle(CryptAuthKeyBundle::Name::kUserKeyPair)); + CryptAuthKeyBundle::Name::kUserKeyPair); + expected_key_bundle.AddKey( + expected_new_keys.find(CryptAuthKeyBundle::Name::kUserKeyPair)->second); + expected_key_bundle.set_key_directive(expected_new_key_directive); + EXPECT_EQ(expected_key_bundle, *key_registry()->GetKeyBundle( + CryptAuthKeyBundle::Name::kUserKeyPair)); +} + +TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, + SuccessfulEnrollment_NoKeysCreated) { + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, + kOldActiveSymmetricKey); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, + kOldInactiveSymmetricKey); + key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kLegacyMasterKey, + GetSampleOldKeyDirective()); + CryptAuthKeyBundle expected_key_bundle(*key_registry()->GetKeyBundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey)); CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), GetSamplePreviousClientDirectivePolicyReference()); @@ -749,18 +812,19 @@ // but not create any new keys. SyncKeysResponse sync_keys_response = BuildSyncKeysResponse({SyncSingleKeyResponseData( - CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), - {{kOldActiveAsymmetricKeyHandle, SyncSingleKeyResponse::DEACTIVATE}, - {kOldInactiveAsymmetricKeyHandle, + CryptAuthKeyBundle::Name::kLegacyMasterKey, key_registry(), + {{kOldActiveSymmetricKeyHandle, SyncSingleKeyResponse::DEACTIVATE}, + {kOldInactiveSymmetricKeyHandle, SyncSingleKeyResponse::ACTIVATE}} /* handle_to_action_map */, SyncSingleKeyResponse::NONE /* new_key_creation */, base::nullopt /* new_key_type */, base::nullopt /* new_key_directive */)}); SendSyncKeysResponse(sync_keys_response); - expected_key_bundle.SetActiveKey(kOldInactiveAsymmetricKeyHandle); - EXPECT_EQ(expected_key_bundle, *key_registry()->GetKeyBundle( - CryptAuthKeyBundle::Name::kUserKeyPair)); + expected_key_bundle.SetActiveKey(kOldInactiveSymmetricKeyHandle); + EXPECT_EQ(expected_key_bundle, + *key_registry()->GetKeyBundle( + CryptAuthKeyBundle::Name::kLegacyMasterKey)); EXPECT_EQ(CryptAuthEnrollmentResult( CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded, @@ -853,7 +917,7 @@ TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, Failure_InvalidKeyActions_NoActiveKey) { - key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kLegacyMasterKey, kOldActiveAsymmetricKey); CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), @@ -862,8 +926,8 @@ // Try to deactivate the only active key. SyncKeysResponse sync_keys_response = BuildSyncKeysResponse({SyncSingleKeyResponseData( - CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), - {{kOldActiveAsymmetricKeyHandle, + CryptAuthKeyBundle::Name::kLegacyMasterKey, key_registry(), + {{kOldActiveSymmetricKeyHandle, SyncSingleKeyResponse::DEACTIVATE}} /* handle_to_action_map */, SyncSingleKeyResponse::NONE /* new_key_creation */, base::nullopt /* new_key_type */, @@ -899,13 +963,59 @@ } TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, + Failure_InvalidKeyCreationInstructions_UnsupportedUserKeyPairKeyType) { + CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), + GetSamplePreviousClientDirectivePolicyReference()); + + // Instruct client to create a symmetric user key pair. The user key pair is + // heavily protected against anything other than P256. + SyncKeysResponse sync_keys_response = + BuildSyncKeysResponse({SyncSingleKeyResponseData( + CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), + {} /* handle_to_action_map */, + SyncSingleKeyResponse::ACTIVE /* new_key_creation */, + KeyType::RAW256 /* new_key_type */, + base::nullopt /* new_key_directive */)}); + SendSyncKeysResponse(sync_keys_response); + + EXPECT_EQ(CryptAuthEnrollmentResult( + CryptAuthEnrollmentResult::ResultCode:: + kErrorUserKeyPairCreationInstructionsInvalid, + sync_keys_response.client_directive()), + enrollment_result()); +} + +TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, + Failure_InvalidKeyCreationInstructions_NewUserKeyPairMustBeActive) { + CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), + GetSamplePreviousClientDirectivePolicyReference()); + + // Instruct client to create a new, inactive user key pair. Since there can + // only be one user key pair in the bundle, a new one must be active. + SyncKeysResponse sync_keys_response = + BuildSyncKeysResponse({SyncSingleKeyResponseData( + CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), + {} /* handle_to_action_map */, + SyncSingleKeyResponse::INACTIVE /* new_key_creation */, + KeyType::P256 /* new_key_type */, + base::nullopt /* new_key_directive */)}); + SendSyncKeysResponse(sync_keys_response); + + EXPECT_EQ(CryptAuthEnrollmentResult( + CryptAuthEnrollmentResult::ResultCode:: + kErrorUserKeyPairCreationInstructionsInvalid, + sync_keys_response.client_directive()), + enrollment_result()); +} + +TEST_F(DeviceSyncCryptAuthV2EnrollerImplTest, Failure_InvalidKeyCreationInstructions_NoServerDiffieHellman) { CallEnroll(GetSampleClientMetadata(), GetSampleClientAppMetadata(), GetSamplePreviousClientDirectivePolicyReference()); SyncKeysResponse sync_keys_response = BuildSyncKeysResponse({SyncSingleKeyResponseData( - CryptAuthKeyBundle::Name::kUserKeyPair, key_registry(), + CryptAuthKeyBundle::Name::kLegacyMasterKey, key_registry(), {} /* handle_to_action_map */, SyncSingleKeyResponse::ACTIVE /* new_key_creation */, KeyType::RAW256 /* new_key_type */, @@ -941,7 +1051,7 @@ {CryptAuthKeyBundle::Name::kUserKeyPair, CryptAuthKey(kNewPublicKey, kNewPrivateKey, CryptAuthKey::Status::kActive, KeyType::P256, - kFixedUserKeyPairHandle)}}; + kCryptAuthFixedUserKeyPairHandle)}}; RunKeyCreator(expected_new_keys, kClientEphemeralDh); EXPECT_EQ(CryptAuthEnrollmentResult(CryptAuthEnrollmentResult::ResultCode:: @@ -980,7 +1090,7 @@ {CryptAuthKeyBundle::Name::kUserKeyPair, CryptAuthKey(kNewPublicKey, kNewPrivateKey, CryptAuthKey::Status::kActive, KeyType::P256, - kFixedUserKeyPairHandle)}}; + kCryptAuthFixedUserKeyPairHandle)}}; RunKeyCreator(expected_new_keys, kClientEphemeralDh); FailEnrollKeysRequest(NetworkRequestError::kBadRequest); @@ -1049,7 +1159,7 @@ {CryptAuthKeyBundle::Name::kUserKeyPair, CryptAuthKey(kNewPublicKey, kNewPrivateKey, CryptAuthKey::Status::kActive, KeyType::P256, - kFixedUserKeyPairHandle)}}; + kCryptAuthFixedUserKeyPairHandle)}}; RunKeyCreator(expected_new_keys, kClientEphemeralDh); // Timeout waiting for EnrollKeysResponse.
diff --git a/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.cc b/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.cc index 225b4b1..58fed3c 100644 --- a/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.cc +++ b/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.cc
@@ -24,12 +24,13 @@ base::Optional<std::string> FakeCryptAuthKeyProofComputer::ComputeKeyProof( const CryptAuthKey& key, const std::string& payload, - const std::string& salt) { + const std::string& salt, + const base::Optional<std::string>& info) { if (should_return_null_) return base::nullopt; - return kFakeKeyProofPrefix + std::string("_") + key.handle() + - std::string("_") + payload + std::string("_") + salt; + return kFakeKeyProofPrefix + std::string("_") + std::string("_") + payload + + std::string("_") + salt + (info ? "_" + *info : ""); } } // namespace device_sync
diff --git a/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.h b/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.h index bd7c017..02a2dd9 100644 --- a/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.h +++ b/chromeos/services/device_sync/fake_cryptauth_key_proof_computer.h
@@ -8,6 +8,8 @@ #include <string> #include "base/macros.h" +#include "base/optional.h" +#include "chromeos/services/device_sync/cryptauth_key_bundle.h" #include "chromeos/services/device_sync/cryptauth_key_proof_computer.h" namespace chromeos { @@ -22,10 +24,12 @@ ~FakeCryptAuthKeyProofComputer() override; // CryptAuthKeyProofComputer: - // Returns "fake_key_proof_<key handle>_<payload>_<salt>". - base::Optional<std::string> ComputeKeyProof(const CryptAuthKey& key, - const std::string& payload, - const std::string& salt) override; + // Returns "fake_key_proof_|payload|>_<|salt|_|info (if not null)|". + base::Optional<std::string> ComputeKeyProof( + const CryptAuthKey& key, + const std::string& payload, + const std::string& salt, + const base::Optional<std::string>& info) override; void set_should_return_null(bool should_return_null) { should_return_null_ = should_return_null;
diff --git a/components/BUILD.gn b/components/BUILD.gn index 68fcbda..4dbc6a7 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -369,8 +369,7 @@ if (enable_print_preview) { deps += [ "//components/pwg_encoder:unit_tests" ] } - - if (safe_browsing_mode == 1) { + if (safe_browsing_mode == 1 || safe_browsing_mode == 3) { deps += [ "//components/safe_browsing/db:unit_tests_desktop" ] } else if (safe_browsing_mode == 2) { deps += [ "//components/safe_browsing/android:unit_tests_mobile" ]
diff --git a/components/autofill/content/renderer/page_form_analyser_logger.cc b/components/autofill/content/renderer/page_form_analyser_logger.cc index 40676ca..88821bf 100644 --- a/components/autofill/content/renderer/page_form_analyser_logger.cc +++ b/components/autofill/content/renderer/page_form_analyser_logger.cc
@@ -6,7 +6,11 @@ #include <utility> +#include "base/strings/string_util.h" #include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/public/web/web_element.h" +#include "third_party/blink/public/web/web_input_element.h" +#include "third_party/blink/public/web/web_node.h" namespace autofill { @@ -38,11 +42,31 @@ text.clear(); text += "[DOM] "; text += entry.message; - for (unsigned i = 0; i < entry.nodes.size(); ++i) - text += " %o"; + + std::vector<blink::WebNode> nodesToLog; + for (unsigned i = 0; i < entry.nodes.size(); ++i) { + if (entry.nodes[i].IsElementNode()) { + const blink::WebElement element = + entry.nodes[i].ToConst<blink::WebElement>(); + const blink::WebInputElement* webInputElement = + blink::ToWebInputElement(&element); + + // Filter out password inputs with values from being logged, as their + // values are also logged. + const bool shouldObfuscate = + webInputElement && + webInputElement->IsPasswordFieldForAutofill() && + !webInputElement->Value().IsEmpty(); + + if (!shouldObfuscate) { + text += " %o"; + nodesToLog.push_back(element); + } + } + } blink::WebConsoleMessage message(level, blink::WebString::FromUTF8(text)); - message.nodes = std::move(entry.nodes); // avoids copying node vectors. + message.nodes = std::move(nodesToLog); // avoids copying node vectors. frame_->AddMessageToConsole(message); } }
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 9b95c9fa..fea04db 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -129,6 +129,7 @@ "form_structure.h", "form_types.cc", "form_types.h", + "label_formatter.cc", "label_formatter.h", "label_formatter_utils.cc", "label_formatter_utils.h",
diff --git a/components/autofill/core/browser/address_form_label_formatter.cc b/components/autofill/core/browser/address_form_label_formatter.cc index 1cd38ac6..604dd78 100644 --- a/components/autofill/core/browser/address_form_label_formatter.cc +++ b/components/autofill/core/browser/address_form_label_formatter.cc
@@ -10,13 +10,11 @@ const std::string& app_locale, ServerFieldType focused_field_type, const std::vector<ServerFieldType>& field_types) - : app_locale_(app_locale), - focused_field_type_(focused_field_type), - field_types_(field_types) { + : LabelFormatter(app_locale, focused_field_type, field_types) { for (const ServerFieldType& type : field_types) { - if ((type != ADDRESS_HOME_COUNTRY) && (type != ADDRESS_BILLING_COUNTRY) && - (type != focused_field_type_)) { - filtered_field_types_.push_back(type); + if (type != focused_field_type && type != ADDRESS_HOME_COUNTRY && + type != ADDRESS_BILLING_COUNTRY) { + field_types_for_labels_.push_back(type); } } }
diff --git a/components/autofill/core/browser/address_form_label_formatter.h b/components/autofill/core/browser/address_form_label_formatter.h index e08a45d..1f0c485 100644 --- a/components/autofill/core/browser/address_form_label_formatter.h +++ b/components/autofill/core/browser/address_form_label_formatter.h
@@ -19,33 +19,19 @@ // with name and address fields and without email or phone fields. class AddressFormLabelFormatter : public LabelFormatter { public: - explicit AddressFormLabelFormatter( - const std::string& app_locale, - ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types); + AddressFormLabelFormatter(const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types); + ~AddressFormLabelFormatter() override; std::vector<base::string16> GetLabels( const std::vector<AutofillProfile*>& profiles) const override; private: - // The locale for which to generate labels. This reflects the language and - // country for which the application is translated, e.g. en_AU for Austalian - // English. - std::string app_locale_; - - // The field on which the user is currently focused. - ServerFieldType focused_field_type_; - - // A collection of meaningful field types in the form with which the user is - // interacting. The NO_SERVER_DATA and UNKNOWN_TYPE field types are not - // considered meaningful. - std::vector<ServerFieldType> field_types_; - - // A collection of meaningful field types excluding the focused_field_type_ - // and ADDRESS_HOME_COUNTRY and ADDRESS_BILLING_COUNTRY. These types are used - // to construct the labels. - std::vector<ServerFieldType> filtered_field_types_; + // A collection of field types that can be used to make labels. This + // collection excludes the focused_field_type_ and address countries. + std::vector<ServerFieldType> field_types_for_labels_; }; } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index 5803d9f7..39c2314 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -114,6 +114,8 @@ // All the required conditions were satisfied even though the form is // unfocused after the user entered information into it. UPLOAD_OFFERED_FROM_NON_FOCUSABLE_FIELD = 1 << 15, + // The card does not satisfy any of the ranges of supported BIN ranges. + UPLOAD_NOT_OFFERED_UNSUPPORTED_BIN_RANGE = 1 << 16, // Update |kNumCardUploadDecisionMetrics| when adding new enum here. }; @@ -1235,7 +1237,7 @@ private: static void Log(AutocompleteEvent event); - static const int kNumCardUploadDecisionMetrics = 16; + static const int kNumCardUploadDecisionMetrics = 17; DISALLOW_IMPLICIT_CONSTRUCTORS(AutofillMetrics); };
diff --git a/components/autofill/core/browser/contact_form_label_formatter.cc b/components/autofill/core/browser/contact_form_label_formatter.cc index 7db04dd..47701675 100644 --- a/components/autofill/core/browser/contact_form_label_formatter.cc +++ b/components/autofill/core/browser/contact_form_label_formatter.cc
@@ -9,15 +9,19 @@ ContactFormLabelFormatter::ContactFormLabelFormatter( const std::string& app_locale, ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types) - : app_locale_(app_locale), - focused_field_type_(focused_field_type), - field_types_(field_types) { + const std::vector<ServerFieldType>& field_types, + const std::set<FieldTypeGroup>& field_type_groups) + : LabelFormatter(app_locale, focused_field_type, field_types), + field_type_groups_(field_type_groups), + filtered_field_type_groups_(field_type_groups) { for (const ServerFieldType& type : field_types) { - if (type != focused_field_type_) { - filtered_field_types_.push_back(type); + if (type != focused_field_type) { + field_types_for_labels_.push_back(type); } } + const FieldTypeGroup group = + AutofillType(AutofillType(focused_field_type).GetStorableType()).group(); + filtered_field_type_groups_.erase(group); } ContactFormLabelFormatter::~ContactFormLabelFormatter() {}
diff --git a/components/autofill/core/browser/contact_form_label_formatter.h b/components/autofill/core/browser/contact_form_label_formatter.h index 47fd10d..3868497 100644 --- a/components/autofill/core/browser/contact_form_label_formatter.h +++ b/components/autofill/core/browser/contact_form_label_formatter.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CONTACT_FORM_LABEL_FORMATTER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_CONTACT_FORM_LABEL_FORMATTER_H_ +#include <set> #include <string> #include <vector> @@ -19,32 +20,28 @@ // containing name and phone or email fields. class ContactFormLabelFormatter : public LabelFormatter { public: - explicit ContactFormLabelFormatter( - const std::string& app_locale, - ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types); + ContactFormLabelFormatter(const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types, + const std::set<FieldTypeGroup>& field_type_groups); + ~ContactFormLabelFormatter() override; std::vector<base::string16> GetLabels( const std::vector<AutofillProfile*>& profiles) const override; private: - // The locale for which to generate labels. This reflects the language and - // country for which the application is translated, e.g. en_AU for Austalian - // English. - std::string app_locale_; + // A collection of field types that can be used to make labels. This + // collection excludes the focused_field_type_. + std::vector<ServerFieldType> field_types_for_labels_; - // The field on which the user is currently focused. - ServerFieldType focused_field_type_; + // A collection of meaningful FieldTypeGroups in the form with which the user + // is interacting. + std::set<FieldTypeGroup> field_type_groups_; - // A collection of meaningful field types in the form with which the user is - // interacting. The NO_SERVER_DATA and UNKNOWN_TYPE field types are not - // considered meaningful. - std::vector<ServerFieldType> field_types_; - - // A collection of meaningful field types excluding the focused_field_type_. - // These types are used to construct the labels. - std::vector<ServerFieldType> filtered_field_types_; + // A collection of meaningful FieldTypeGroups in the form with which the user + // is interacting minus the focused field's corresponding FieldTypeGroup. + std::set<FieldTypeGroup> filtered_field_type_groups_; }; } // namespace autofill
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc index 84e8922..6aa41e8e 100644 --- a/components/autofill/core/browser/credit_card_save_manager.cc +++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -420,8 +420,8 @@ show_save_prompt_ = num_strikes < kMaxStrikesToPreventPoppingUpOfferToSavePrompt; - // Only offer upload once both Payments and the Autofill LegacyStrikeDatabase - // have returned their decisions. Use population of + // Only offer upload once both Payments and the Autofill + // LegacyStrikeDatabase have returned their decisions. Use population of // |upload_request_.context_token| as an indicator of the Payments call // returning successfully. if (!upload_request_.context_token.empty()) @@ -431,12 +431,24 @@ void CreditCardSaveManager::OnDidGetUploadDetails( AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::Value> legal_message) { + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_card_bin_ranges) { if (observer_for_testing_) observer_for_testing_->OnReceivedGetUploadDetailsResponse(); if (result == AutofillClient::SUCCESS) { // Do *not* call payments_client_->Prepare() here. We shouldn't send // credentials until the user has explicitly accepted a prompt to upload. + if (base::FeatureList::IsEnabled( + features::kAutofillDoNotUploadSaveUnsupportedCards) && + !supported_card_bin_ranges.empty() && + !IsCreditCardSupported(supported_card_bin_ranges)) { + AttemptToOfferCardLocalSave(has_non_focusable_field_, + upload_request_.card); + upload_decision_metrics_ |= + AutofillMetrics::UPLOAD_NOT_OFFERED_UNSUPPORTED_BIN_RANGE; + LogCardUploadDecisions(upload_decision_metrics_); + return; + } upload_request_.context_token = context_token; legal_message_ = base::DictionaryValue::From(std::move(legal_message)); @@ -1057,4 +1069,28 @@ } } +bool CreditCardSaveManager::IsCreditCardSupported( + std::vector<std::pair<int, int>> supported_card_bin_ranges) { + base::string16 stripped_number = + CreditCard::StripSeparators(upload_request_.card.number()); + for (auto& bin_range : supported_card_bin_ranges) { + unsigned long range_num_of_digits = + base::NumberToString(bin_range.first).size(); + DCHECK_EQ(range_num_of_digits, + base::NumberToString(bin_range.second).size()); + // The first n digits of credit card number, where n is the number of + // digits in range's starting/ending number. + int first_digits_start, first_digits_end; + base::StringToInt(stripped_number.substr(0, range_num_of_digits), + &first_digits_start); + base::StringToInt(stripped_number.substr(0, range_num_of_digits), + &first_digits_end); + if (first_digits_start >= bin_range.first && + first_digits_end <= bin_range.second) { + return true; + } + } + return false; +} + } // namespace autofill
diff --git a/components/autofill/core/browser/credit_card_save_manager.h b/components/autofill/core/browser/credit_card_save_manager.h index f6fd234..5cffff6 100644 --- a/components/autofill/core/browser/credit_card_save_manager.h +++ b/components/autofill/core/browser/credit_card_save_manager.h
@@ -8,6 +8,7 @@ #include <map> #include <memory> #include <string> +#include <utility> #include <vector> #include "base/optional.h" @@ -153,10 +154,14 @@ // Returns the legal message retrieved from Payments. On failure or not // meeting Payments's conditions for upload, |legal_message| will contain - // nullptr. - void OnDidGetUploadDetails(AutofillClient::PaymentsRpcResult result, - const base::string16& context_token, - std::unique_ptr<base::Value> legal_message); + // nullptr. |supported_card_bin_ranges| is a list of BIN prefix ranges which + // are supoorted, with the first and second number in the pair being the start + // and end of the range. + void OnDidGetUploadDetails( + AutofillClient::PaymentsRpcResult result, + const base::string16& context_token, + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_card_bin_ranges); // Logs the number of strikes that a card had when save succeeded. void LogStrikesPresentWhenCardSaved(bool is_local, const int num_strikes); @@ -259,6 +264,13 @@ // Logs the reason why expiration date was explicitly requested. void LogSaveCardRequestExpirationDateReasonMetric(); + // Checks if credit card matches one of the ranges in + // |supported_card_bin_ranges|, inclusive of the start and end boundaries. + // For example, if the range consists of std::pair<34, 36>, then all cards + // with first two digits of 34, 35 and 36 are supported. + bool IsCreditCardSupported( + std::vector<std::pair<int, int>> supported_card_bin_ranges); + // For testing. void SetEventObserverForTesting(ObserverForTest* observer) { observer_for_testing_ = observer; @@ -335,6 +347,8 @@ std::unique_ptr<LocalCardMigrationStrikeDatabase> local_card_migration_strike_database_; + std::unique_ptr<CreditCardSaveStrikeDatabase> strike_database_; + // May be null. ObserverForTest* observer_for_testing_ = nullptr;
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc index af7d56d8..ec4e91e3 100644 --- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -5509,4 +5509,61 @@ EXPECT_EQ(local_card_migration_strike_database.GetStrikes(), 3); } +// Tests that if a card doesn't fall in any of the supported bin ranges, local +// save is offered rather than upload save. +TEST_F(CreditCardSaveManagerTest, UploadSaveNotOfferedForUnsupportedCard) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillDoNotUploadSaveUnsupportedCards); + std::vector<std::pair<int, int>> supported_card_bin_ranges{ + std::make_pair(4111, 4113), std::make_pair(34, 34), + std::make_pair(300, 305)}; + payments_client_->SetSupportedBINRanges(supported_card_bin_ranges); + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("5454545454545454"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Since card isn't in any of the supported ranges, local save should be + // offered and upload save should not. + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); +} + +// Tests that if a card falls in one of the supported bin ranges, upload save +// is offered. +TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillDoNotUploadSaveUnsupportedCards); + // Set supported BIN ranges. + std::vector<std::pair<int, int>> supported_card_bin_ranges{ + std::make_pair(4111, 4113)}; + payments_client_->SetSupportedBINRanges(supported_card_bin_ranges); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Since card is in one of the supported ranges(4111-4113), upload save should + // be offered. + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter.cc b/components/autofill/core/browser/label_formatter.cc new file mode 100644 index 0000000..32426dd --- /dev/null +++ b/components/autofill/core/browser/label_formatter.cc
@@ -0,0 +1,17 @@ +// Copyright 2019 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/autofill/core/browser/label_formatter.h" + +namespace autofill { + +LabelFormatter::LabelFormatter(const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types) + : app_locale_(app_locale), + focused_field_type_(focused_field_type), + field_types_(field_types) {} +LabelFormatter::~LabelFormatter() = default; + +} // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter.h b/components/autofill/core/browser/label_formatter.h index a4061809..d4364010 100644 --- a/components/autofill/core/browser/label_formatter.h +++ b/components/autofill/core/browser/label_formatter.h
@@ -17,11 +17,35 @@ // Handles the creation of Suggestions' disambiguating labels. class LabelFormatter { public: - virtual ~LabelFormatter() = default; + LabelFormatter(const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types); + virtual ~LabelFormatter(); + // Returns a collection of |labels| formed by extracting useful disambiguating // information from a collection of |profiles|. virtual std::vector<base::string16> GetLabels( const std::vector<AutofillProfile*>& profiles) const = 0; + + protected: + const std::string& app_locale() const { return app_locale_; } + ServerFieldType focused_field_type() const { return focused_field_type_; } + const std::vector<ServerFieldType>& field_types() const { + return field_types_; + } + + private: + // The locale for which to generate labels. This reflects the language and + // country for which the application is translated, e.g. en_AU for Austalian + // English. + std::string app_locale_; + + // The field on which the user is currently focused. + ServerFieldType focused_field_type_; + + // A collection of meaningful field types in the form with which the user is + // interacting. + std::vector<ServerFieldType> field_types_; }; } // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter_utils.cc b/components/autofill/core/browser/label_formatter_utils.cc index aae4a090..53d8eab 100644 --- a/components/autofill/core/browser/label_formatter_utils.cc +++ b/components/autofill/core/browser/label_formatter_utils.cc
@@ -7,22 +7,64 @@ #include <memory> #include <set> +#include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/address_form_label_formatter.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/contact_form_label_formatter.h" +#include "components/autofill/core/browser/validation.h" namespace autofill { namespace { -// Returns true if |type| belongs to the NAME FieldTypeGroup. Note that billing -// ServerFieldTypes are converted to their non-billing types. -bool FieldTypeIsName(const ServerFieldType& type) { - FieldTypeGroup focused_field_group = - AutofillType(AutofillType(type).GetStorableType()).group(); - return focused_field_group == NAME; +bool ContainsName(uint32_t groups) { + return groups & label_formatter_groups::kName; +} + +bool ContainsAddress(uint32_t groups) { + return groups & label_formatter_groups::kAddress; +} + +bool ContainsEmail(uint32_t groups) { + return groups & label_formatter_groups::kEmail; +} + +bool ContainsPhone(uint32_t groups) { + return groups & label_formatter_groups::kPhone; +} + +std::set<FieldTypeGroup> GetFieldTypeGroups(uint32_t groups) { + std::set<FieldTypeGroup> field_type_groups; + if (ContainsName(groups)) { + field_type_groups.insert(NAME); + } + if (ContainsAddress(groups)) { + field_type_groups.insert(ADDRESS_HOME); + } + if (ContainsEmail(groups)) { + field_type_groups.insert(EMAIL); + } + if (ContainsPhone(groups)) { + field_type_groups.insert(PHONE_HOME); + } + return field_type_groups; } } // namespace +std::vector<ServerFieldType> FilterFieldTypes( + const std::vector<ServerFieldType>& field_types) { + std::vector<ServerFieldType> filtered_field_types; + for (const ServerFieldType& field_type : field_types) { + const FieldTypeGroup group = + AutofillType(AutofillType(field_type).GetStorableType()).group(); + if (group == NAME || group == ADDRESS_HOME || group == EMAIL || + group == PHONE_HOME) { + filtered_field_types.push_back(field_type); + } + } + return filtered_field_types; +} + uint32_t DetermineGroups(const std::vector<ServerFieldType>& field_types) { uint32_t group_bitmask = 0; for (const ServerFieldType& type : field_types) { @@ -42,7 +84,7 @@ group_bitmask |= label_formatter_groups::kPhone; break; default: - group_bitmask |= label_formatter_groups::kUnsupported; + break; } } return group_bitmask; @@ -52,34 +94,22 @@ const std::string& app_locale, ServerFieldType focused_field_type, const std::vector<ServerFieldType>& field_types) { - if (!FieldTypeIsName(focused_field_type)) { + const uint32_t groups = DetermineGroups(field_types); + + if (!ContainsName(groups)) { return nullptr; } - - std::vector<ServerFieldType> filtered_field_types; - for (const ServerFieldType& field_type : field_types) { - // NO_SERVER_DATA fields are frequently found in the collection of field - // types sent from the frontend. UKNOWN_TYPE fields represent various form - // elements, e.g. checkboxes. Neither field type is useful to the formatter, - // so they are excluded from its collection of field types. - if (field_type != NO_SERVER_DATA && field_type != UNKNOWN_TYPE) { - filtered_field_types.push_back(field_type); - } - } - - const uint32_t groups = DetermineGroups(filtered_field_types); - if (groups == - (label_formatter_groups::kName | label_formatter_groups::kAddress)) { + if (ContainsAddress(groups) && !ContainsEmail(groups) && + !ContainsPhone(groups)) { return std::make_unique<AddressFormLabelFormatter>( - app_locale, focused_field_type, filtered_field_types); + app_locale, focused_field_type, FilterFieldTypes(field_types)); } - - if (groups == - (label_formatter_groups::kName | label_formatter_groups::kPhone | - label_formatter_groups::kEmail)) { + if (ContainsEmail(groups) || ContainsPhone(groups)) { return std::make_unique<ContactFormLabelFormatter>( - app_locale, focused_field_type, filtered_field_types); + app_locale, focused_field_type, FilterFieldTypes(field_types), + GetFieldTypeGroups(groups)); } return nullptr; } + } // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter_utils.h b/components/autofill/core/browser/label_formatter_utils.h index f4c12f4b..80b2194 100644 --- a/components/autofill/core/browser/label_formatter_utils.h +++ b/components/autofill/core/browser/label_formatter_utils.h
@@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_UTILS_H_ #include <memory> +#include <set> #include <string> #include <vector> @@ -16,30 +17,37 @@ namespace label_formatter_groups { // Bits for FieldTypeGroup options. -// The form contains an unsupported field. -constexpr uint32_t kUnsupported = 1 << 0; // The form contains at least one field associated with the NAME_HOME or // NAME_BILLING FieldTypeGroups. -constexpr uint32_t kName = 1 << 1; +constexpr uint32_t kName = 1 << 0; // The form contains at least one field associated with the ADDRESS_HOME or // ADDRESS_BILLING FieldTypeGroups. -constexpr uint32_t kAddress = 1 << 2; +constexpr uint32_t kAddress = 1 << 1; // The form contains at least one field associated with the EMAIL // FieldTypeGroup. -constexpr uint32_t kEmail = 1 << 3; +constexpr uint32_t kEmail = 1 << 2; // The form contains at least one field associated with the PHONE_HOME or // PHONE_BILLING FieldTypeGroup. -constexpr uint32_t kPhone = 1 << 4; +constexpr uint32_t kPhone = 1 << 3; } // namespace label_formatter_groups -// Returns a bitmask indicating the FieldTypeGroups associated with the given -// |field_types|. +// Returns a subset of meaningful ServerFieldTypes found in |field_types|. +// ServerFieldTypes like NO_SERVER_DATA and UNKNOWN_TYPE are frequently found in +// the collection of types sent from the frontend. Other types, e.g. +// COMPANY_NAME and PHONE_FAX_WHOLE_NUMBER, are also sometimes present. These +// types are not useful to LabelFormatters, so only types related to names, +// addresses, emails, and phone numbers are in the results. +std::vector<ServerFieldType> FilterFieldTypes( + const std::vector<ServerFieldType>& field_types); + +// Returns a bitmask indicating whether the NAME, ADDRESS_HOME, EMAIL, and +// PHONE_HOME FieldTypeGroups are associated with the given |field_types|. uint32_t DetermineGroups(const std::vector<ServerFieldType>& field_types); // Creates a form-specific LabelFormatter according to |field_types|. If the -// given |focused_field_type| and |field_types| do not correspond to a -// LabelFormatter, then nullptr will be returned. +// given |field_types| do not correspond to a LabelFormatter, then nullptr will +// be returned. std::unique_ptr<LabelFormatter> Create( const std::string& app_locale, ServerFieldType focused_field_type,
diff --git a/components/autofill/core/browser/label_formatter_utils_unittest.cc b/components/autofill/core/browser/label_formatter_utils_unittest.cc index 0542d2c..660cb02 100644 --- a/components/autofill/core/browser/label_formatter_utils_unittest.cc +++ b/components/autofill/core/browser/label_formatter_utils_unittest.cc
@@ -13,9 +13,35 @@ using label_formatter_groups::kEmail; using label_formatter_groups::kName; using label_formatter_groups::kPhone; -using label_formatter_groups::kUnsupported; + } // namespace +TEST(LabelFormatterUtilsTest, FilterFieldTypesNoFiltering) { + const std::vector<ServerFieldType> field_types{ + NAME_LAST, NAME_BILLING_LAST, ADDRESS_HOME_ZIP, + ADDRESS_BILLING_ZIP, EMAIL_ADDRESS, PHONE_HOME_NUMBER, + PHONE_BILLING_NUMBER}; + const std::vector<ServerFieldType> filtered_field_types = + FilterFieldTypes(field_types); + EXPECT_EQ(field_types, filtered_field_types); +} + +TEST(LabelFormatterUtilsTest, FilterFieldTypesFilterCompany) { + const std::vector<ServerFieldType> field_types{NAME_LAST, COMPANY_NAME}; + const std::vector<ServerFieldType> expected_filtered_field_types{NAME_LAST}; + const std::vector<ServerFieldType> filtered_field_types = + FilterFieldTypes(field_types); + EXPECT_EQ(expected_filtered_field_types, filtered_field_types); +} + +TEST(LabelFormatterUtilsTest, FilterFieldTypesForNoGivenFieldTypes) { + const std::vector<ServerFieldType> field_types = + std::vector<ServerFieldType>(); + const std::vector<ServerFieldType> filtered_field_types = + FilterFieldTypes(field_types); + EXPECT_EQ(field_types, filtered_field_types); +} + TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNameAndAddress) { const std::vector<ServerFieldType> field_types{ NAME_FIRST, NAME_LAST, ADDRESS_HOME_LINE1, @@ -36,7 +62,7 @@ EXPECT_EQ(expected_group_bitmask, group_bitmask); } -TEST(LabelFormatterUtilsTest, DetermineGroupsForNameHomePhoneAndEmail) { +TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNamePhoneAndEmail) { const std::vector<ServerFieldType> field_types{ NAME_FULL, PHONE_HOME_CITY_AND_NUMBER, EMAIL_ADDRESS}; @@ -45,7 +71,7 @@ EXPECT_EQ(expected_group_bitmask, group_bitmask); } -TEST(LabelFormatterUtilsTest, DetermineGroupsForNameBillingPhoneAndEmail) { +TEST(LabelFormatterUtilsTest, DetermineGroupsForBillingNamePhoneAndEmail) { const std::vector<ServerFieldType> field_types{ NAME_BILLING_FULL, PHONE_BILLING_WHOLE_NUMBER, EMAIL_ADDRESS}; @@ -58,7 +84,7 @@ const std::vector<ServerFieldType> field_types{UNKNOWN_TYPE, NAME_FULL, ADDRESS_HOME_ZIP}; - const uint32_t expected_group_bitmask = kName | kAddress | kUnsupported; + const uint32_t expected_group_bitmask = kName | kAddress; const uint32_t group_bitmask = DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -71,4 +97,4 @@ EXPECT_EQ(expected_group_bitmask, group_bitmask); } -} // namespace autofill +} // namespace autofill \ No newline at end of file
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc index ab4fb69..e82bb52 100644 --- a/components/autofill/core/browser/local_card_migration_manager.cc +++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -232,7 +232,8 @@ bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::Value> legal_message) { + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_card_bin_ranges) { if (observer_for_testing_) observer_for_testing_->OnReceivedGetUploadDetailsResponse();
diff --git a/components/autofill/core/browser/local_card_migration_manager.h b/components/autofill/core/browser/local_card_migration_manager.h index a040d1f..02365d3 100644 --- a/components/autofill/core/browser/local_card_migration_manager.h +++ b/components/autofill/core/browser/local_card_migration_manager.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <utility> #include <vector> #include "base/strings/string16.h" @@ -134,7 +135,8 @@ bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::Value> legal_message); + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_card_bin_ranges); // Callback after successfully getting the migration save results. Map // migration save result to each card depending on the |save_result|. Will
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc index fe22763..3fda27d8 100644 --- a/components/autofill/core/browser/payments/payments_client.cc +++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -343,7 +343,8 @@ const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> callback, + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback, const int billable_service_number, PaymentsClient::UploadCardSource upload_card_source) : addresses_(addresses), @@ -442,6 +443,16 @@ base::Value* dictionary_value = response.FindKey("legal_message"); if (dictionary_value) legal_message_ = std::make_unique<base::Value>(dictionary_value->Clone()); + + base::Value* list_ptr = response.FindKey("supported_card_bin_ranges"); + if (list_ptr && list_ptr->is_list()) { + for (base::Value& result : list_ptr->GetList()) { + DCHECK(result.is_dict()); + base::Optional<int> start = response.FindIntKey("start"); + base::Optional<int> end = response.FindIntKey("end"); + supported_card_bin_ranges_.push_back(std::make_pair(*start, *end)); + } + } } bool IsResponseComplete() override { @@ -449,7 +460,8 @@ } void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { - std::move(callback_).Run(result, context_token_, std::move(legal_message_)); + std::move(callback_).Run(result, context_token_, std::move(legal_message_), + supported_card_bin_ranges_); } private: @@ -460,10 +472,12 @@ std::string app_locale_; base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback_; base::string16 context_token_; std::unique_ptr<base::Value> legal_message_; + std::vector<std::pair<int, int>> supported_card_bin_ranges_; const int billable_service_number_; PaymentsClient::UploadCardSource upload_card_source_; }; @@ -771,7 +785,8 @@ const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> callback, + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback, const int billable_service_number, UploadCardSource upload_card_source) { IssueRequest(
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h index be0bc53..ad6c075 100644 --- a/components/autofill/core/browser/payments/payments_client.h +++ b/components/autofill/core/browser/payments/payments_client.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_ +#include <utility> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" @@ -178,7 +180,8 @@ const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> callback, + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback, const int billable_service_number, UploadCardSource upload_card_source = UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE);
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc index 2d3e5350..6f9edce 100644 --- a/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -119,11 +119,14 @@ real_pan_ = real_pan; } - void OnDidGetUploadDetails(AutofillClient::PaymentsRpcResult result, - const base::string16& context_token, - std::unique_ptr<base::Value> legal_message) { + void OnDidGetUploadDetails( + AutofillClient::PaymentsRpcResult result, + const base::string16& context_token, + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_card_bin_ranges) { result_ = result; legal_message_ = std::move(legal_message); + supported_card_bin_ranges_ = supported_card_bin_ranges; } void OnDidUploadCard(AutofillClient::PaymentsRpcResult result, @@ -237,6 +240,7 @@ std::string server_id_; std::string real_pan_; std::unique_ptr<base::Value> legal_message_; + std::vector<std::pair<int, int>> supported_card_bin_ranges_; std::vector<MigratableCreditCard> migratable_credit_cards_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; std::string display_text_;
diff --git a/components/autofill/core/browser/payments/test_payments_client.cc b/components/autofill/core/browser/payments/test_payments_client.cc index 8bf0f86a..e58fe67 100644 --- a/components/autofill/core/browser/payments/test_payments_client.cc +++ b/components/autofill/core/browser/payments/test_payments_client.cc
@@ -30,7 +30,8 @@ const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> callback, + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback, const int billable_service_number, PaymentsClient::UploadCardSource upload_card_source) { upload_details_addresses_ = addresses; @@ -38,11 +39,11 @@ active_experiments_ = active_experiments; billable_service_number_ = billable_service_number; upload_card_source_ = upload_card_source; - std::move(callback).Run(app_locale == "en-US" - ? AutofillClient::SUCCESS - : AutofillClient::PERMANENT_FAILURE, - base::ASCIIToUTF16("this is a context token"), - std::unique_ptr<base::Value>(nullptr)); + std::move(callback).Run( + app_locale == "en-US" ? AutofillClient::SUCCESS + : AutofillClient::PERMANENT_FAILURE, + base::ASCIIToUTF16("this is a context token"), + std::unique_ptr<base::Value>(nullptr), supported_card_bin_ranges_); } void TestPaymentsClient::UploadCard( @@ -71,5 +72,10 @@ save_result_ = std::move(save_result); } +void TestPaymentsClient::SetSupportedBINRanges( + std::vector<std::pair<int, int>> bin_ranges) { + supported_card_bin_ranges_ = bin_ranges; +} + } // namespace payments } // namespace autofill
diff --git a/components/autofill/core/browser/payments/test_payments_client.h b/components/autofill/core/browser/payments/test_payments_client.h index 01e9d00..e7f6c928 100644 --- a/components/autofill/core/browser/payments/test_payments_client.h +++ b/components/autofill/core/browser/payments/test_payments_client.h
@@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_ #include <string> +#include <utility> #include <vector> #include "components/autofill/core/browser/payments/payments_client.h" @@ -34,7 +35,8 @@ const std::string& app_locale, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, const base::string16&, - std::unique_ptr<base::Value>)> callback, + std::unique_ptr<base::Value>, + std::vector<std::pair<int, int>>)> callback, const int billable_service_number, UploadCardSource upload_card_source = UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) override; @@ -55,6 +57,8 @@ std::unique_ptr<std::unordered_map<std::string, std::string>> save_result); + void SetSupportedBINRanges(std::vector<std::pair<int, int>> bin_ranges); + int detected_values_in_upload_details() const { return detected_values_; } const std::vector<AutofillProfile>& addresses_in_upload_details() const { return upload_details_addresses_; @@ -74,6 +78,7 @@ private: std::string server_id_; + std::vector<std::pair<int, int>> supported_card_bin_ranges_; std::vector<AutofillProfile> upload_details_addresses_; std::vector<AutofillProfile> upload_card_addresses_; int detected_values_;
diff --git a/components/autofill/core/browser/test_local_card_migration_manager.cc b/components/autofill/core/browser/test_local_card_migration_manager.cc index 0438e64..b9808476 100644 --- a/components/autofill/core/browser/test_local_card_migration_manager.cc +++ b/components/autofill/core/browser/test_local_card_migration_manager.cc
@@ -76,11 +76,13 @@ bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::Value> legal_message) { + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_bin_ranges) { if (result == AutofillClient::SUCCESS) { local_card_migration_was_triggered_ = true; LocalCardMigrationManager::OnDidGetUploadDetails( - is_from_settings_page, result, context_token, std::move(legal_message)); + is_from_settings_page, result, context_token, std::move(legal_message), + supported_bin_ranges); } }
diff --git a/components/autofill/core/browser/test_local_card_migration_manager.h b/components/autofill/core/browser/test_local_card_migration_manager.h index fe5e6f8a..722d366 100644 --- a/components/autofill/core/browser/test_local_card_migration_manager.h +++ b/components/autofill/core/browser/test_local_card_migration_manager.h
@@ -5,7 +5,10 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ +#include <memory> #include <string> +#include <utility> +#include <vector> #include "components/autofill/core/browser/local_card_migration_manager.h" #include "components/autofill/core/browser/sync_utils.h" @@ -60,7 +63,8 @@ bool is_from_settings_page, AutofillClient::PaymentsRpcResult result, const base::string16& context_token, - std::unique_ptr<base::Value> legal_message) override; + std::unique_ptr<base::Value> legal_message, + std::vector<std::pair<int, int>> supported_bin_ranges) override; bool local_card_migration_was_triggered_ = false;
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index 5bed4234..4783ffa 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -67,6 +67,10 @@ const base::Feature kAutofillDeleteDisusedCreditCards{ "AutofillDeleteDisusedCreditCards", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillDoNotUploadSaveUnsupportedCards{ + "AutofillDoNotUploadSaveUnsupportedCards", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether the credit card downstream keyboard accessory shows // the Google Pay logo animation on iOS. const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index a7a832b..492f662a 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -33,6 +33,7 @@ extern const base::Feature kAutofillCreditCardLocalCardMigration; extern const base::Feature kAutofillDeleteDisusedAddresses; extern const base::Feature kAutofillDeleteDisusedCreditCards; +extern const base::Feature kAutofillDoNotUploadSaveUnsupportedCards; extern const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS; extern const base::Feature kAutofillDynamicForms; extern const base::Feature kAutofillEnableAccountWalletStorage;
diff --git a/components/autofill/ios/browser/resources/autofill_controller.js b/components/autofill/ios/browser/resources/autofill_controller.js index ec5477b5..2172b64 100644 --- a/components/autofill/ios/browser/resources/autofill_controller.js +++ b/components/autofill/ios/browser/resources/autofill_controller.js
@@ -256,7 +256,7 @@ if (!__gCrWeb.autofill.styleInjected) { var style = document.createElement('style'); style.textContent = '[chrome-autofilled] {' + - 'background-color:#FAFFBD !important;' + + 'background-color:#E8F0FE !important;' + 'background-image:none !important;' + 'color:#000000 !important;' + '}';
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index 0bffb91..145f7d0f 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -23,6 +23,7 @@ sources = [ "metrics.h", "overlay_state.h", + "payment_request.h", ] }
diff --git a/components/autofill_assistant/browser/actions/get_payment_information_action.cc b/components/autofill_assistant/browser/actions/get_payment_information_action.cc index 7b838dd1..dff48e8 100644 --- a/components/autofill_assistant/browser/actions/get_payment_information_action.cc +++ b/components/autofill_assistant/browser/actions/get_payment_information_action.cc
@@ -119,7 +119,8 @@ } processed_action_proto_->mutable_payment_details() ->set_is_terms_and_conditions_accepted( - payment_information->is_terms_and_conditions_accepted); + payment_information->terms_and_conditions == + TermsAndConditionsState::ACCEPTED); processed_action_proto_->mutable_payment_details()->set_payer_email( payment_information->payer_email); }
diff --git a/components/autofill_assistant/browser/chip.h b/components/autofill_assistant/browser/chip.h index 941b5a410..c030529 100644 --- a/components/autofill_assistant/browser/chip.h +++ b/components/autofill_assistant/browser/chip.h
@@ -20,13 +20,16 @@ Chip(Chip&&); Chip& operator=(Chip&&); - ChipType type; + ChipType type = UNKNOWN_CHIP_TYPE; // Localized string to display. std::string text; // Callback triggered when the chip is tapped. base::OnceClosure callback; + + // Whether this chip is disabled. + bool disabled = false; }; // Guarantees that the Chip.type of all chips is set to a sensible value.
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc index b0df135..4b98e1f 100644 --- a/components/autofill_assistant/browser/controller.cc +++ b/components/autofill_assistant/browser/controller.cc
@@ -210,8 +210,6 @@ return; } - // If the button clicked is not the Cancel button, then we clear the - // current chips and run the callback. auto callback = std::move((*chips)[chip_index].callback); SetChips(nullptr); std::move(callback).Run(); @@ -600,14 +598,105 @@ return payment_request_options_.get(); } -void Controller::SetPaymentInformation( - std::unique_ptr<PaymentInformation> payment_information) { - if (!payment_request_options_) +void Controller::OnPaymentRequestContinueButtonClicked() { + if (!payment_request_options_ || !payment_request_info_) return; auto callback = std::move(payment_request_options_->callback); + auto payment_request_info = std::move(payment_request_info_); + + // TODO(crbug.com/806868): succeed is currently always true, but we might want + // to set it to false and propagate the result to GetPaymentInformationAction + // when the user clicks "Cancel" during that action. + payment_request_info->succeed = true; + SetPaymentRequestOptions(nullptr); - std::move(callback).Run(std::move(payment_information)); + std::move(callback).Run(std::move(payment_request_info)); +} + +void Controller::SetShippingAddress( + std::unique_ptr<autofill::AutofillProfile> address) { + if (!payment_request_info_) + return; + + payment_request_info_->shipping_address = std::move(address); + UpdatePaymentRequestActions(); +} + +void Controller::SetBillingAddress( + std::unique_ptr<autofill::AutofillProfile> address) { + if (!payment_request_info_) + return; + + payment_request_info_->billing_address = std::move(address); + UpdatePaymentRequestActions(); +} + +void Controller::SetContactInfo(std::string name, + std::string phone, + std::string email) { + if (!payment_request_info_) + return; + + payment_request_info_->payer_name = name; + payment_request_info_->payer_phone = phone; + payment_request_info_->payer_email = email; + UpdatePaymentRequestActions(); +} + +void Controller::SetCreditCard(std::unique_ptr<autofill::CreditCard> card) { + if (!payment_request_info_) + return; + + payment_request_info_->card = std::move(card); + UpdatePaymentRequestActions(); +} + +void Controller::SetTermsAndConditions( + TermsAndConditionsState terms_and_conditions) { + if (!payment_request_info_) + return; + + payment_request_info_->terms_and_conditions = terms_and_conditions; + UpdatePaymentRequestActions(); +} + +void Controller::UpdatePaymentRequestActions() { + // TODO(crbug.com/806868): This method uses #SetChips(), which means that + // updating the PR actions will also clear the suggestions. We should update + // the actions only if there are use cases of PR + suggestions. + if (!payment_request_options_ || !payment_request_info_) { + return; + } + + bool contact_info_ok = (!payment_request_options_->request_payer_name || + !payment_request_info_->payer_name.empty()) && + (!payment_request_options_->request_payer_email || + !payment_request_info_->payer_email.empty()) && + (!payment_request_options_->request_payer_phone || + !payment_request_info_->payer_phone.empty()); + + bool shipping_address_ok = !payment_request_options_->request_shipping || + payment_request_info_->shipping_address; + + bool terms_ok = payment_request_info_->terms_and_conditions != NOT_SELECTED; + + bool continue_button_enabled = contact_info_ok && shipping_address_ok && + payment_request_info_->card && terms_ok; + + auto chips = std::make_unique<std::vector<Chip>>(); + chips->emplace_back(); + chips->back().text = + l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_PAYMENT_INFO_CONFIRM); + chips->back().type = HIGHLIGHTED_ACTION; + chips->back().disabled = !continue_button_enabled; + if (continue_button_enabled) { + chips->back().callback = + base::BindOnce(&Controller::OnPaymentRequestContinueButtonClicked, + weak_ptr_factory_.GetWeakPtr()); + } + + SetChips(std::move(chips)); } void Controller::GetTouchableArea(std::vector<RectF>* area) const { @@ -767,7 +856,12 @@ if (payment_request_options_ == nullptr && options == nullptr) return; + if (options) { + payment_request_info_ = std::make_unique<PaymentInformation>(); + } + payment_request_options_ = std::move(options); + UpdatePaymentRequestActions(); GetUiController()->OnPaymentRequestChanged(payment_request_options_.get()); }
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h index ba8e478..cbb55e9 100644 --- a/components/autofill_assistant/browser/controller.h +++ b/components/autofill_assistant/browser/controller.h
@@ -111,8 +111,16 @@ void SelectAction(int index) override; std::string GetDebugContext() override; const PaymentRequestOptions* GetPaymentRequestOptions() const override; - void SetPaymentInformation( - std::unique_ptr<PaymentInformation> payment_information) override; + void SetShippingAddress( + std::unique_ptr<autofill::AutofillProfile> address) override; + void SetBillingAddress( + std::unique_ptr<autofill::AutofillProfile> address) override; + void SetContactInfo(std::string name, + std::string phone, + std::string email) override; + void SetCreditCard(std::unique_ptr<autofill::CreditCard> card) override; + void SetTermsAndConditions( + TermsAndConditionsState terms_and_conditions) override; void GetTouchableArea(std::vector<RectF>* area) const override; void OnFatalError(const std::string& error_message, Metrics::DropOutReason reason) override; @@ -164,6 +172,9 @@ // Called when a script is selected. void OnScriptSelected(const std::string& script_path); + void UpdatePaymentRequestActions(); + void OnPaymentRequestContinueButtonClicked(); + // Overrides ScriptTracker::Listener: void OnNoRunnableScripts() override; void OnRunnableScriptsChanged( @@ -258,6 +269,7 @@ bool will_shutdown_ = false; std::unique_ptr<PaymentRequestOptions> payment_request_options_; + std::unique_ptr<PaymentInformation> payment_request_info_; // Tracks scripts and script execution. It's kept at the end, as it tend to // depend on everything the controller support, through script and script
diff --git a/components/autofill_assistant/browser/payment_request.h b/components/autofill_assistant/browser/payment_request.h index 77fa420..db9faa4ed 100644 --- a/components/autofill_assistant/browser/payment_request.h +++ b/components/autofill_assistant/browser/payment_request.h
@@ -18,6 +18,15 @@ namespace autofill_assistant { +// GENERATED_JAVA_ENUM_PACKAGE: ( +// org.chromium.chrome.browser.autofill_assistant.payment) +// GENERATED_JAVA_CLASS_NAME_OVERRIDE: AssistantTermsAndConditionsState +enum TermsAndConditionsState { + NOT_SELECTED = 0, + ACCEPTED = 1, + REQUIRES_REVIEW = 2, +}; + // Struct for holding the payment information data. struct PaymentInformation { PaymentInformation(); @@ -30,7 +39,7 @@ std::string payer_name; std::string payer_phone; std::string payer_email; - bool is_terms_and_conditions_accepted = false; + TermsAndConditionsState terms_and_conditions = NOT_SELECTED; }; // Struct for holding the payment request options.
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h index b9283a4..f9409c8 100644 --- a/components/autofill_assistant/browser/ui_delegate.h +++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -64,10 +64,26 @@ // field contains a non-null options describing the request. virtual const PaymentRequestOptions* GetPaymentRequestOptions() const = 0; - // Sets payment information, in response to the current payment request + // Sets shipping address, in response to the current payment request options. + virtual void SetShippingAddress( + std::unique_ptr<autofill::AutofillProfile> address) = 0; + + // Sets billing address, in response to the current payment request options. + virtual void SetBillingAddress( + std::unique_ptr<autofill::AutofillProfile> address) = 0; + + // Sets contact info, in response to the current payment request options. + virtual void SetContactInfo(std::string name, + std::string phone, + std::string email) = 0; + + // Sets credit card, in response to the current payment request options. + virtual void SetCreditCard(std::unique_ptr<autofill::CreditCard> card) = 0; + + // Sets terms and conditions, in response to the current payment request // options. - virtual void SetPaymentInformation( - std::unique_ptr<PaymentInformation> payment_information) = 0; + virtual void SetTermsAndConditions( + TermsAndConditionsState terms_and_conditions) = 0; // Adds the rectangles that correspond to the current touchable area to the // given vector.
diff --git a/components/autofill_assistant_strings.grdp b/components/autofill_assistant_strings.grdp index daadd1daff..52494ec 100644 --- a/components/autofill_assistant_strings.grdp +++ b/components/autofill_assistant_strings.grdp
@@ -15,6 +15,9 @@ <message name="IDS_AUTOFILL_ASSISTANT_LOADING" desc="Text label that is shown during the loading of the first page, right after being triggered."> Opening <ph name="SITE_NAME">$1<ex>google.com</ex></ph>… </message> + <message name="IDS_AUTOFILL_ASSISTANT_PAYMENT_INFO_CONFIRM" desc="Text on the payment request primary button to confirm payment information [CHAR-LIMIT=32]"> + Continue + </message> <message name="IDS_AUTOFILL_ASSISTANT_DETAILS_DIFFER" desc="Shown as Status Message when details differ."> The screening is different from what you selected. Continue? </message>
diff --git a/components/component_updater/README.md b/components/component_updater/README.md index bf3fc31..a72b22f 100644 --- a/components/component_updater/README.md +++ b/components/component_updater/README.md
@@ -37,7 +37,7 @@ ### Create a CRX Package Signing Key & Manifest (Non-Google) All components are delivered as CRX files (signed ZIP archives). You need to create a signing key. If you are a Googler, follow the instructions at -http://go/newchromecomponents for maximum key security. Otherwise, you can +http://go/newchromecomponent for maximum key security. Otherwise, you can create an RSA key pair using `openssl` or a similar tool. You will additionally need to create a manifest.json file. If nothing else, the
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc index 303e7728..91b5724 100644 --- a/components/cronet/stale_host_resolver.cc +++ b/components/cronet/stale_host_resolver.cc
@@ -17,6 +17,7 @@ #include "base/values.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_util.h" #include "net/dns/host_resolver_source.h" #include "net/log/net_log_with_source.h" @@ -422,7 +423,7 @@ use_stale_on_name_not_resolved(false) {} StaleHostResolver::StaleHostResolver( - std::unique_ptr<net::HostResolverImpl> inner_resolver, + std::unique_ptr<net::ContextHostResolver> inner_resolver, const StaleOptions& stale_options) : inner_resolver_(std::move(inner_resolver)), options_(stale_options),
diff --git a/components/cronet/stale_host_resolver.h b/components/cronet/stale_host_resolver.h index 3f82a9d..11834d9a 100644 --- a/components/cronet/stale_host_resolver.h +++ b/components/cronet/stale_host_resolver.h
@@ -12,18 +12,21 @@ #include "base/time/default_tick_clock.h" #include "net/base/completion_once_callback.h" #include "net/dns/host_resolver.h" -#include "net/dns/host_resolver_impl.h" namespace base { class TickClock; } // namespace base +namespace net { +class ContextHostResolver; +} // namespace net + namespace cronet { namespace { class StaleHostResolverTest; } // namespace -// A HostResolver that wraps a HostResolverImpl and uses it to make requests, +// A HostResolver that wraps a ContextHostResolver and uses it to make requests, // but "impatiently" returns stale data (if available and usable) after a delay, // to reduce DNS latency at the expense of accuracy. class StaleHostResolver : public net::HostResolver { @@ -60,7 +63,7 @@ // Creates a StaleHostResolver that uses |inner_resolver| for actual // resolution, but potentially returns stale data according to // |stale_options|. - StaleHostResolver(std::unique_ptr<net::HostResolverImpl> inner_resolver, + StaleHostResolver(std::unique_ptr<net::ContextHostResolver> inner_resolver, const StaleOptions& stale_options); ~StaleHostResolver() override; @@ -107,9 +110,9 @@ // Set |tick_clock_| for testing. Must be set before issuing any requests. void SetTickClockForTesting(const base::TickClock* tick_clock); - // The underlying HostResolverImpl that will be used to make cache and network - // requests. - std::unique_ptr<net::HostResolverImpl> inner_resolver_; + // The underlying ContextHostResolver that will be used to make cache and + // network requests. + std::unique_ptr<net::ContextHostResolver> inner_resolver_; // Shared instance of tick clock, overridden for testing. const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance();
diff --git a/components/cronet/stale_host_resolver_unittest.cc b/components/cronet/stale_host_resolver_unittest.cc index faa2e152..b5a2543 100644 --- a/components/cronet/stale_host_resolver_unittest.cc +++ b/components/cronet/stale_host_resolver_unittest.cc
@@ -30,6 +30,7 @@ #include "net/base/net_errors.h" #include "net/base/network_change_notifier.h" #include "net/cert/cert_verifier.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_config.h" #include "net/dns/dns_hosts.h" #include "net/dns/dns_test_util.h" @@ -171,14 +172,15 @@ mock_proc_ = new MockHostResolverProc(result); } - std::unique_ptr<net::HostResolverImpl> CreateMockInnerResolverWithDnsClient( + std::unique_ptr<net::ContextHostResolver> + CreateMockInnerResolverWithDnsClient( std::unique_ptr<net::DnsClient> dns_client) { - std::unique_ptr<net::HostResolverImpl> inner_resolver( + std::unique_ptr<net::ContextHostResolver> inner_resolver( net::HostResolver::CreateDefaultResolverImpl(nullptr)); - net::HostResolverImpl::ProcTaskParams proc_params(mock_proc_.get(), 1u); - inner_resolver->set_proc_params_for_test(proc_params); - inner_resolver->SetDnsClient(std::move(dns_client)); + net::ProcTaskParams proc_params(mock_proc_.get(), 1u); + inner_resolver->SetProcParamsForTesting(proc_params); + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); return inner_resolver; }
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc index b02d87e..4b71d49 100644 --- a/components/cronet/url_request_context_config.cc +++ b/components/cronet/url_request_context_config.cc
@@ -24,6 +24,7 @@ #include "net/cert/ct_policy_status.h" #include "net/cert/do_nothing_ct_verifier.h" #include "net/cert/multi_threaded_cert_verifier.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/host_resolver.h" #include "net/dns/mapped_host_resolver.h" #include "net/http/http_network_session.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc index 941b3c8..1aee8f7 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -534,6 +534,23 @@ std::string encoded_config; base::Base64Encode(config_data, &encoded_config); config_storer_.Run(encoded_config); + + // Record timing metrics on successful requests only. + const network::ResourceResponseHead* info = url_loader_->ResponseInfo(); + base::TimeDelta http_request_rtt = + info->response_start - info->request_start; + UMA_HISTOGRAM_TIMES("DataReductionProxy.ConfigService.HttpRequestRTT", + http_request_rtt); + + if (info->load_timing.connect_timing.connect_end > base::TimeTicks() && + info->load_timing.connect_timing.connect_start > base::TimeTicks()) { + base::TimeDelta connection_setup = + info->load_timing.connect_timing.connect_end - + info->load_timing.connect_timing.connect_start; + UMA_HISTOGRAM_TIMES( + "DataReductionProxy.ConfigService.ConnectionSetupTime", + connection_setup); + } } else { ++failed_attempts_before_success_; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc index f73a903d..a04d6c5 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -555,6 +555,8 @@ // Tests that the config is read successfully on the first attempt. TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) { Init(true); + base::HistogramTester histogram_tester; + AddMockSuccess(); SetDataReductionProxyEnabled(true, true); EXPECT_TRUE(configurator()->GetProxyConfig().proxy_rules().empty()); @@ -562,6 +564,8 @@ config_client()->RetrieveConfig(); RunUntilIdle(); VerifyRemoteSuccess(true); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigService.HttpRequestRTT", 1); EXPECT_FALSE(configurator()->GetProxyConfig().proxy_rules().empty()); #if defined(OS_ANDROID) EXPECT_FALSE(config_client()->foreground_fetch_pending()); @@ -650,6 +654,8 @@ histogram_tester.ExpectUniqueSample( "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 1, 1); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.ConfigService.HttpRequestRTT", 1); } // Verifies that the config is fetched successfully after IP address changes.
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc index 80a7b22..f9ec2f1d 100644 --- a/components/download/internal/common/download_stats.cc +++ b/components/download/internal/common/download_stats.cc
@@ -401,43 +401,44 @@ FILE_PATH_LITERAL(".settingcontent-ms"), FILE_PATH_LITERAL(".oxt"), // 317 FILE_PATH_LITERAL(".pyd"), - FILE_PATH_LITERAL(".pyo"), // 319 - FILE_PATH_LITERAL(".desktop"), // 320 - FILE_PATH_LITERAL(".cpi"), // 321 - FILE_PATH_LITERAL(".jpg"), // 322 - FILE_PATH_LITERAL(".jpeg"), // 323 - FILE_PATH_LITERAL(".mp3"), // 324 - FILE_PATH_LITERAL(".mp4"), // 325 - FILE_PATH_LITERAL(".png"), // 326 - FILE_PATH_LITERAL(".xls"), // 327 - FILE_PATH_LITERAL(".doc"), // 328 - FILE_PATH_LITERAL(".pptx"), // 329 - FILE_PATH_LITERAL(".csv"), // 330 - FILE_PATH_LITERAL(".ica"), // 331 - FILE_PATH_LITERAL(".ppt"), // 332 - FILE_PATH_LITERAL(".gif"), // 333 - FILE_PATH_LITERAL(".txt"), // 334 - FILE_PATH_LITERAL(".package"), // 335 - FILE_PATH_LITERAL(".tif"), // 336 - FILE_PATH_LITERAL(".rtf"), // 337 - FILE_PATH_LITERAL(".webp"), // 338 - FILE_PATH_LITERAL(".mkv"), // 339 - FILE_PATH_LITERAL(".wav"), // 340 - FILE_PATH_LITERAL(".mov"), // 341 - FILE_PATH_LITERAL(".dot"), // 342 - FILE_PATH_LITERAL(".dotx"), // 343 - FILE_PATH_LITERAL(".xlsb"), // 344 - FILE_PATH_LITERAL(".xlt"), // 345 - FILE_PATH_LITERAL(".xlm"), // 346 - FILE_PATH_LITERAL(".xldm"), // 347 - FILE_PATH_LITERAL(".xla"), // 348 - FILE_PATH_LITERAL(".xlam"), // 349 - FILE_PATH_LITERAL(".xll"), // 350 - FILE_PATH_LITERAL(".xlw"), // 351 - FILE_PATH_LITERAL(".pot"), // 352 - FILE_PATH_LITERAL(".potm"), // 353 - FILE_PATH_LITERAL(".ppsm"), // 354 - FILE_PATH_LITERAL(".pps"), // 355 + FILE_PATH_LITERAL(".pyo"), // 319 + FILE_PATH_LITERAL(".desktop"), // 320 + FILE_PATH_LITERAL(".cpi"), // 321 + FILE_PATH_LITERAL(".jpg"), // 322 + FILE_PATH_LITERAL(".jpeg"), // 323 + FILE_PATH_LITERAL(".mp3"), // 324 + FILE_PATH_LITERAL(".mp4"), // 325 + FILE_PATH_LITERAL(".png"), // 326 + FILE_PATH_LITERAL(".xls"), // 327 + FILE_PATH_LITERAL(".doc"), // 328 + FILE_PATH_LITERAL(".pptx"), // 329 + FILE_PATH_LITERAL(".csv"), // 330 + FILE_PATH_LITERAL(".ica"), // 331 + FILE_PATH_LITERAL(".ppt"), // 332 + FILE_PATH_LITERAL(".gif"), // 333 + FILE_PATH_LITERAL(".txt"), // 334 + FILE_PATH_LITERAL(".package"), // 335 + FILE_PATH_LITERAL(".tif"), // 336 + FILE_PATH_LITERAL(".rtf"), // 337 + FILE_PATH_LITERAL(".webp"), // 338 + FILE_PATH_LITERAL(".mkv"), // 339 + FILE_PATH_LITERAL(".wav"), // 340 + FILE_PATH_LITERAL(".mov"), // 341 + FILE_PATH_LITERAL(".dot"), // 342 + FILE_PATH_LITERAL(".dotx"), // 343 + FILE_PATH_LITERAL(".xlsb"), // 344 + FILE_PATH_LITERAL(".xlt"), // 345 + FILE_PATH_LITERAL(".xlm"), // 346 + FILE_PATH_LITERAL(".xldm"), // 347 + FILE_PATH_LITERAL(".xla"), // 348 + FILE_PATH_LITERAL(".xlam"), // 349 + FILE_PATH_LITERAL(".xll"), // 350 + FILE_PATH_LITERAL(".xlw"), // 351 + FILE_PATH_LITERAL(".pot"), // 352 + FILE_PATH_LITERAL(".potm"), // 353 + FILE_PATH_LITERAL(".ppsm"), // 354 + FILE_PATH_LITERAL(".pps"), // 355 + FILE_PATH_LITERAL(".mobileconfig"), // 356 // NOTE! When you add a type here, please add the UMA value as a comment. // These must all match DownloadItem.DangerousFileType in // enums.xml. From 263 onward, they should also match
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index 184287f..cb691a5 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -542,10 +542,13 @@ const gfx::Rect& window_bounds, int bounds_change) { // 1) Do no update the bounds unless we have geometry from client. - // 2) Do not update the bounds if window is minimized. + // 2) Do not update the bounds if window is minimized unless it + // exiting the minimzied state. // The bounds will be provided by client when unminimized. if (!geometry().IsEmpty() && !window_bounds.IsEmpty() && - !widget_->IsMinimized() && bounds_changed_callback_) { + (!widget_->IsMinimized() || + requested_state != ash::mojom::WindowStateType::MINIMIZED) && + bounds_changed_callback_) { // Sends the client bounds, which matches the geometry // when frame is enabled. ash::NonClientFrameViewAsh* frame_view = GetFrameView();
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 15b50bde..84e8fbc 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1850,6 +1850,12 @@ ash::mojom::WindowStateType::MINIMIZED, 0, gfx::Rect(0, 0, 100, 100), 0); ASSERT_EQ(1, bounds_change_count()); + + // Send bounds change when exiting minmized. + shell_surface->OnBoundsChangeEvent(ash::mojom::WindowStateType::MINIMIZED, + ash::mojom::WindowStateType::NORMAL, 0, + gfx::Rect(0, 0, 100, 100), 0); + ASSERT_EQ(2, bounds_change_count()); } TEST_F(ClientControlledShellSurfaceTest, SetPipWindowBoundsAnimates) {
diff --git a/components/feed/content/feed_offline_host.cc b/components/feed/content/feed_offline_host.cc index b47ebda..d1b0dfd 100644 --- a/components/feed/content/feed_offline_host.cc +++ b/components/feed/content/feed_offline_host.cc
@@ -25,12 +25,6 @@ namespace { -// |url| is always set. Sometimes |original_url| is set. If |original_url| is -// set it is returned by this method, otherwise fall back to |url|. -const GURL& PreferOriginal(const OfflinePageItem& item) { - return item.original_url.is_empty() ? item.url : item.original_url; -} - // Aggregates multiple callbacks from OfflinePageModel, storing the offline url. // When all callbacks have been invoked, tracked by ref counting, then // |on_completeion_| is finally invoked, sending all results together. @@ -255,7 +249,7 @@ void FeedOfflineHost::OfflinePageAdded(OfflinePageModel* model, const OfflinePageItem& added_page) { DCHECK(!notify_status_change_.is_null()); - const std::string& url = PreferOriginal(added_page).spec(); + const std::string& url = added_page.GetOriginalUrl().spec(); CacheOfflinePageUrlAndId(url, added_page.offline_id); notify_status_change_.Run(url, true); }
diff --git a/components/feed/content/feed_offline_host_unittest.cc b/components/feed/content/feed_offline_host_unittest.cc index 6d03c13..d2e052f 100644 --- a/components/feed/content/feed_offline_host_unittest.cc +++ b/components/feed/content/feed_offline_host_unittest.cc
@@ -57,7 +57,7 @@ std::string name_space) { OfflinePageItem item; item.url = GURL(url); - item.original_url = GURL(original_url); + item.original_url_if_different = GURL(original_url); item.offline_id = offline_id; item.creation_time = creation_time; item.client_id = offline_pages::ClientId(name_space, ""); @@ -373,7 +373,7 @@ TEST_F(FeedOfflineHostTest, OfflinePageAdded) { OfflinePageItem added_page; added_page.url = GURL(kUrl1); - added_page.original_url = GURL(kUrl2); + added_page.original_url_if_different = GURL(kUrl2); added_page.offline_id = 4; host()->OfflinePageAdded(nullptr, added_page);
diff --git a/components/feed/core/feed_logging_metrics.cc b/components/feed/core/feed_logging_metrics.cc index 1d9eaeec..29f2f72 100644 --- a/components/feed/core/feed_logging_metrics.cc +++ b/components/feed/core/feed_logging_metrics.cc
@@ -28,7 +28,11 @@ // identical bucket sizes and names with Zine is for comparing Feed with Zine // easily. After Zine is deprecated, we can change the values if we needed. +// Constants used as max sample sizes for histograms. +const int kMaxContentCount = 50; +const int kMaxFailureCount = 10; const int kMaxSuggestionsTotal = 50; +const int kMaxTokenCount = 10; // Keep in sync with MAX_SUGGESTIONS_PER_SECTION in NewTabPageUma.java. const int kMaxSuggestionsForArticle = 20; @@ -335,6 +339,70 @@ } } +void FeedLoggingMetrics::OnInternalError(int internal_error) { + // TODO(https://crbug.com/935602): The max value here is fragile, figure out + // some way to test the @IntDef size. + UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.InternalError", + internal_error, 10); +} + +void FeedLoggingMetrics::OnTokenCompleted(bool was_synthetic, + int content_count, + int token_count) { + if (was_synthetic) { + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenCompleted.ContentCount.Synthetic", + content_count, kMaxFailureCount); + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenCompleted.TokenCount.Synthetic", + token_count, kMaxTokenCount); + } else { + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenCompleted.ContentCount.Nonsynthetic", + content_count, kMaxContentCount); + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenCompleted.TokenCount.Nonsynthetic", + token_count, kMaxTokenCount); + } +} + +void FeedLoggingMetrics::OnTokenFailedToComplete(bool was_synthetic, + int failure_count) { + if (was_synthetic) { + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenFailedToCompleted.Synthetic", + failure_count, kMaxFailureCount); + } else { + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.TokenFailedToCompleted.Nonsynthetic", + failure_count, kMaxFailureCount); + } +} + +void FeedLoggingMetrics::OnServerRequest(int request_reason) { + // TODO(https://crbug.com/935602): The max value here is fragile, figure out + // some way to test the @IntDef size. + UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.ServerRequest.Reason", + request_reason, 8); +} + +void FeedLoggingMetrics::OnZeroStateShown(int zero_state_show_reason) { + // TODO(https://crbug.com/935602): The max value here is fragile, figure out + // some way to test the @IntDef size. + UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.ZeroStateShown.Reason", + zero_state_show_reason, 3); +} + +void FeedLoggingMetrics::OnZeroStateRefreshCompleted(int new_content_count, + int new_token_count) { + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.ZeroStateRefreshCompleted.ContentCount", + new_content_count, kMaxContentCount); + UMA_HISTOGRAM_EXACT_LINEAR( + "ContentSuggestions.Feed.ZeroStateRefreshCompleted.TokenCount", + new_token_count, kMaxTokenCount); +} + void FeedLoggingMetrics::ReportScrolledAfterOpen() { base::RecordAction(base::UserMetricsAction("Suggestions.ScrolledAfterOpen")); }
diff --git a/components/feed/core/feed_logging_metrics.h b/components/feed/core/feed_logging_metrics.h index 975d9212..2b1984cc 100644 --- a/components/feed/core/feed_logging_metrics.h +++ b/components/feed/core/feed_logging_metrics.h
@@ -89,6 +89,18 @@ void OnPietFrameRenderingEvent(std::vector<int> piet_error_codes); + void OnInternalError(int internal_error); + + void OnTokenCompleted(bool was_synthetic, int content_count, int token_count); + + void OnTokenFailedToComplete(bool was_synthetic, int failure_count); + + void OnServerRequest(int request_reason); + + void OnZeroStateShown(int zero_state_show_reason); + + void OnZeroStateRefreshCompleted(int new_content_count, int new_token_count); + void ReportScrolledAfterOpen(); private:
diff --git a/components/feed/core/feed_scheduler_host.h b/components/feed/core/feed_scheduler_host.h index eb43b69..d2455de 100644 --- a/components/feed/core/feed_scheduler_host.h +++ b/components/feed/core/feed_scheduler_host.h
@@ -226,7 +226,7 @@ throttlers_; // Status of the last fetch for debugging. - int last_fetch_status_; + int last_fetch_status_ = 0; DISALLOW_COPY_AND_ASSIGN(FeedSchedulerHost); };
diff --git a/components/gwp_asan/client/guarded_page_allocator.cc b/components/gwp_asan/client/guarded_page_allocator.cc index 13fc2bf..483c425 100644 --- a/components/gwp_asan/client/guarded_page_allocator.cc +++ b/components/gwp_asan/client/guarded_page_allocator.cc
@@ -76,8 +76,8 @@ std::next(free_slot_ring_buffer_.begin(), total_pages)); } - slots_ = std::make_unique<AllocatorState::SlotMetadata[]>(total_pages); - state_.slot_metadata = reinterpret_cast<uintptr_t>(slots_.get()); + metadata_ = std::make_unique<AllocatorState::SlotMetadata[]>(total_pages); + state_.metadata_addr = reinterpret_cast<uintptr_t>(metadata_.get()); } GuardedPageAllocator::~GuardedPageAllocator() { @@ -128,13 +128,13 @@ // Check for a call to free() with an incorrect pointer (e.g. the pointer does // not match the allocated pointer.) - if (addr != slots_[slot].alloc_ptr) { + if (addr != metadata_[slot].alloc_ptr) { state_.free_invalid_address = addr; __builtin_trap(); } // Check for double free. - if (slots_[slot].deallocation_occurred.exchange(true)) { + if (metadata_[slot].deallocation_occurred.exchange(true)) { state_.double_free_address = addr; // TODO(https://crbug.com/925447): The other thread may not be done writing // a stack trace so we could spin here until it's read; however, it's also @@ -156,8 +156,8 @@ CHECK(PointerIsMine(ptr)); const uintptr_t addr = reinterpret_cast<uintptr_t>(ptr); size_t slot = state_.AddrToSlot(state_.GetPageAddr(addr)); - DCHECK_EQ(addr, slots_[slot].alloc_ptr); - return slots_[slot].alloc_size; + DCHECK_EQ(addr, metadata_[slot].alloc_ptr); + return metadata_[slot].alloc_size; } size_t GuardedPageAllocator::RegionSize() const { @@ -194,34 +194,35 @@ void GuardedPageAllocator::RecordAllocationMetadata(size_t slot, size_t size, void* ptr) { - slots_[slot].alloc_size = size; - slots_[slot].alloc_ptr = reinterpret_cast<uintptr_t>(ptr); + metadata_[slot].alloc_size = size; + metadata_[slot].alloc_ptr = reinterpret_cast<uintptr_t>(ptr); void* trace[AllocatorState::kMaxStackFrames]; size_t len = base::debug::CollectStackTrace(trace, AllocatorState::kMaxStackFrames); - slots_[slot].alloc.trace_len = Pack(reinterpret_cast<uintptr_t*>(trace), len, - slots_[slot].alloc.packed_trace, - sizeof(slots_[slot].alloc.packed_trace)); - slots_[slot].alloc.tid = ReportTid(); - slots_[slot].alloc.trace_collected = true; + metadata_[slot].alloc.trace_len = + Pack(reinterpret_cast<uintptr_t*>(trace), len, + metadata_[slot].alloc.packed_trace, + sizeof(metadata_[slot].alloc.packed_trace)); + metadata_[slot].alloc.tid = ReportTid(); + metadata_[slot].alloc.trace_collected = true; - slots_[slot].dealloc.tid = base::kInvalidThreadId; - slots_[slot].dealloc.trace_len = 0; - slots_[slot].dealloc.trace_collected = false; - slots_[slot].deallocation_occurred = false; + metadata_[slot].dealloc.tid = base::kInvalidThreadId; + metadata_[slot].dealloc.trace_len = 0; + metadata_[slot].dealloc.trace_collected = false; + metadata_[slot].deallocation_occurred = false; } void GuardedPageAllocator::RecordDeallocationMetadata(size_t slot) { void* trace[AllocatorState::kMaxStackFrames]; size_t len = base::debug::CollectStackTrace(trace, AllocatorState::kMaxStackFrames); - slots_[slot].dealloc.trace_len = + metadata_[slot].dealloc.trace_len = Pack(reinterpret_cast<uintptr_t*>(trace), len, - slots_[slot].dealloc.packed_trace, - sizeof(slots_[slot].dealloc.packed_trace)); - slots_[slot].dealloc.tid = ReportTid(); - slots_[slot].dealloc.trace_collected = true; + metadata_[slot].dealloc.packed_trace, + sizeof(metadata_[slot].dealloc.packed_trace)); + metadata_[slot].dealloc.tid = ReportTid(); + metadata_[slot].dealloc.trace_collected = true; } uintptr_t GuardedPageAllocator::GetCrashKeyAddress() const {
diff --git a/components/gwp_asan/client/guarded_page_allocator.h b/components/gwp_asan/client/guarded_page_allocator.h index a4ace98..4ca13eb8 100644 --- a/components/gwp_asan/client/guarded_page_allocator.h +++ b/components/gwp_asan/client/guarded_page_allocator.h
@@ -124,7 +124,7 @@ // We dynamically allocate the SlotMetadata array to avoid allocating // extraneous memory for when total_pages < kGpaMaxPages. - std::unique_ptr<AllocatorState::SlotMetadata[]> slots_; + std::unique_ptr<AllocatorState::SlotMetadata[]> metadata_; // Required for a singleton to access the constructor. friend base::NoDestructor<GuardedPageAllocator>;
diff --git a/components/gwp_asan/client/gwp_asan.cc b/components/gwp_asan/client/gwp_asan.cc index e5eb6e2..1f64ea3 100644 --- a/components/gwp_asan/client/gwp_asan.cc +++ b/components/gwp_asan/client/gwp_asan.cc
@@ -23,26 +23,35 @@ namespace internal { namespace { +constexpr int kDefaultMaxAllocations = 7; +constexpr int kDefaultTotalPages = 30; +constexpr int kDefaultAllocationSamplingFrequency = 1000; +constexpr double kDefaultProcessSamplingProbability = 1.0; +constexpr int kDefaultIncreasedMemoryMultiplier = 4; + const base::Feature kGwpAsan{"GwpAsanMalloc", base::FEATURE_DISABLED_BY_DEFAULT}; const base::FeatureParam<int> kMaxAllocationsParam{&kGwpAsan, "MaxAllocations", - 7}; + kDefaultMaxAllocations}; -const base::FeatureParam<int> kTotalPagesParam{&kGwpAsan, "TotalPages", 30}; +const base::FeatureParam<int> kTotalPagesParam{&kGwpAsan, "TotalPages", + kDefaultTotalPages}; const base::FeatureParam<int> kAllocationSamplingParam{ - &kGwpAsan, "AllocationSamplingFrequency", 1000}; + &kGwpAsan, "AllocationSamplingFrequency", + kDefaultAllocationSamplingFrequency}; const base::FeatureParam<double> kProcessSamplingParam{ - &kGwpAsan, "ProcessSamplingProbability", 1.0}; + &kGwpAsan, "ProcessSamplingProbability", + kDefaultProcessSamplingProbability}; // The multiplier to increase MaxAllocations/TotalPages in scenarios where we // want to perform additional testing (e.g. on canary/dev builds or in the // browser process.) The multiplier increase is cumulative when multiple // conditions apply. const base::FeatureParam<int> kIncreasedMemoryMultiplierParam{ - &kGwpAsan, "IncreasedMemoryMultiplier", 4}; + &kGwpAsan, "IncreasedMemoryMultiplier", kDefaultIncreasedMemoryMultiplier}; bool EnableForMalloc(bool is_canary_dev, bool is_browser_process) { if (!base::FeatureList::IsEnabled(kGwpAsan))
diff --git a/components/gwp_asan/common/allocator_state.cc b/components/gwp_asan/common/allocator_state.cc index 8aa839f..937b1bb 100644 --- a/components/gwp_asan/common/allocator_state.cc +++ b/components/gwp_asan/common/allocator_state.cc
@@ -31,7 +31,7 @@ if (slot_idx >= kGpaMaxPages) return GetMetadataReturnType::kErrorBadSlot; - *slot_address = slot_metadata + (slot_idx * sizeof(SlotMetadata)); + *slot_address = metadata_addr + (slot_idx * sizeof(SlotMetadata)); return GetMetadataReturnType::kGwpAsanCrash; } @@ -53,7 +53,7 @@ pages_end_addr - pages_base_addr != page_size * (total_pages * 2 + 1)) return false; - if (!slot_metadata) + if (!metadata_addr) return false; return true; @@ -91,12 +91,12 @@ AllocatorState::ErrorType AllocatorState::GetErrorType(uintptr_t addr, bool allocated, bool deallocated) const { + if (free_invalid_address) + return ErrorType::kFreeInvalidAddress; if (!allocated) return ErrorType::kUnknown; if (double_free_address) return ErrorType::kDoubleFree; - if (free_invalid_address) - return ErrorType::kFreeInvalidAddress; if (deallocated) return ErrorType::kUseAfterFree; if (addr < first_page_addr)
diff --git a/components/gwp_asan/common/allocator_state.h b/components/gwp_asan/common/allocator_state.h index 3bc19eb8..74de37d 100644 --- a/components/gwp_asan/common/allocator_state.h +++ b/components/gwp_asan/common/allocator_state.h
@@ -140,7 +140,7 @@ // Pointer to an array of metadata about every allocation, including its size, // offset, and pointers to the allocation/deallocation stack traces (if // present.) - uintptr_t slot_metadata = 0; + uintptr_t metadata_addr = 0; // Set to the address of a double freed allocation if a double free occurred. uintptr_t double_free_address = 0;
diff --git a/components/gwp_asan/common/allocator_state_unittest.cc b/components/gwp_asan/common/allocator_state_unittest.cc index 1d029115f..44cff48e 100644 --- a/components/gwp_asan/common/allocator_state_unittest.cc +++ b/components/gwp_asan/common/allocator_state_unittest.cc
@@ -33,7 +33,7 @@ end_addr_offset + base + page_size * (total_pages * 2 + 1); // An invalid address, but it's never dereferenced in AllocatorState. - state_.slot_metadata = 0x1234; + state_.metadata_addr = 0x1234; } AllocatorState state_; @@ -110,5 +110,16 @@ AllocatorState::ErrorType::kBufferOverflow); } +// Correctly handle the edge case when a free() occurs on a page that has never +// been allocated. +TEST_F(AllocatorStateTest, GetErrorTypeFreeInvalidAddressEdgeCase) { + InitializeState(base::GetPageSize(), kGpaMaxPages); + EXPECT_TRUE(state_.IsValid()); + + state_.free_invalid_address = state_.first_page_addr; + EXPECT_EQ(state_.GetErrorType(state_.first_page_addr, false, false), + AllocatorState::ErrorType::kFreeInvalidAddress); +} + } // namespace internal } // namespace gwp_asan
diff --git a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc index d70dc34..f9b5807 100644 --- a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc +++ b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
@@ -19,12 +19,6 @@ offline_pages::kSuggestedArticlesNamespace; } -const GURL& GetOfflinePageUrl(const OfflinePageItem& offline_page_item) { - return offline_page_item.original_url != GURL() - ? offline_page_item.original_url - : offline_page_item.url; -} - } // namespace PrefetchedPagesTrackerImpl::PrefetchedPagesTrackerImpl( @@ -119,7 +113,7 @@ void PrefetchedPagesTrackerImpl::AddOfflinePage( const OfflinePageItem& offline_page_item) { - const GURL& url = GetOfflinePageUrl(offline_page_item); + const GURL& url = offline_page_item.GetOriginalUrl(); DCHECK(prefetched_url_counts_.count(url) == 0 || prefetched_url_counts_.find(url)->second > 0); ++prefetched_url_counts_[url];
diff --git a/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc b/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc index d76ea9d..f58eaea 100644 --- a/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc +++ b/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
@@ -140,7 +140,7 @@ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com"))); tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo( item.offline_id, kSystemDownloadId, item.client_id, - /*request_origin=*/"", item.original_url)); + /*request_origin=*/"", item.original_url_if_different)); EXPECT_FALSE( tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com"))); } @@ -163,7 +163,8 @@ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo( manually_downloaded_item.offline_id, kSystemDownloadId, manually_downloaded_item.client_id, - /*request_origin=*/"", manually_downloaded_item.original_url)); + /*request_origin=*/"", + manually_downloaded_item.original_url_if_different)); EXPECT_TRUE( tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com"))); } @@ -274,7 +275,7 @@ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo( first_item.offline_id, kSystemDownloadId, first_item.client_id, - /*request_origin=*/"", first_item.original_url)); + /*request_origin=*/"", first_item.original_url_if_different)); // Only one offline page (out of two) has been removed, the remaining one // should be reported here. @@ -299,14 +300,14 @@ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo( first_item.offline_id, kSystemDownloadId, first_item.client_id, - /*request_origin=*/"", first_item.original_url)); + /*request_origin=*/"", first_item.original_url_if_different)); ASSERT_TRUE( tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com"))); tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo( second_item.offline_id, kSystemDownloadId, second_item.client_id, - /*request_origin=*/"", second_item.original_url)); + /*request_origin=*/"", second_item.original_url_if_different)); // All offline pages have been removed, their absence should be reported here. EXPECT_FALSE(
diff --git a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc index c8dc249..4de15b8 100644 --- a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc +++ b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -158,7 +158,7 @@ if (page.second.client_id.id == guid) { DeletedPageInfo info(page.second.offline_id, kSystemDownloadId, page.second.client_id, page.second.request_origin, - page.second.original_url); + page.second.original_url_if_different); observer_->OfflinePageDeleted(info); pages.erase(page.first); return;
diff --git a/components/offline_pages/core/downloads/offline_item_conversions.cc b/components/offline_pages/core/downloads/offline_item_conversions.cc index 33ebda4..7223f834 100644 --- a/components/offline_pages/core/downloads/offline_item_conversions.cc +++ b/components/offline_pages/core/downloads/offline_item_conversions.cc
@@ -57,7 +57,7 @@ item.file_path = page.file_path; item.mime_type = GetMimeType(); item.page_url = page.url; - item.original_url = page.original_url; + item.original_url = page.original_url_if_different; item.progress.value = 100; item.progress.max = 100; item.progress.unit = OfflineItemProgressUnit::PERCENTAGE;
diff --git a/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc b/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc index ed972349..3aa47c8e 100644 --- a/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc +++ b/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc
@@ -39,7 +39,7 @@ OfflinePageItem offline_page_item(kTestUrl, offline_id, client_id, file_path, file_size, creation_time); - offline_page_item.original_url = kTestOriginalUrl; + offline_page_item.original_url_if_different = kTestOriginalUrl; offline_page_item.title = base::UTF8ToUTF16(title); offline_page_item.last_access_time = last_access_time; offline_page_item.file_missing_time = base::Time::Now();
diff --git a/components/offline_pages/core/model/add_page_task.cc b/components/offline_pages/core/model/add_page_task.cc index f8f601a0..cd4e73e 100644 --- a/components/offline_pages/core/model/add_page_task.cc +++ b/components/offline_pages/core/model/add_page_task.cc
@@ -57,7 +57,7 @@ statement.BindInt64(7, store_utils::ToDatabaseTime(item.last_access_time)); statement.BindInt(8, item.access_count); statement.BindString16(9, item.title); - statement.BindString(10, item.original_url.spec()); + statement.BindString(10, item.original_url_if_different.spec()); statement.BindString(11, item.request_origin); statement.BindInt64(12, item.system_download_id); statement.BindInt64(13, store_utils::ToDatabaseTime(item.file_missing_time));
diff --git a/components/offline_pages/core/model/add_page_task_unittest.cc b/components/offline_pages/core/model/add_page_task_unittest.cc index bca504c..dde4408 100644 --- a/components/offline_pages/core/model/add_page_task_unittest.cc +++ b/components/offline_pages/core/model/add_page_task_unittest.cc
@@ -95,7 +95,7 @@ kTestFilePath, kTestFileSize, base::Time::Now(), kTestOrigin); page.title = kTestTitle; - page.original_url = kTestUrl2; + page.original_url_if_different = kTestUrl2; page.system_download_id = kTestDownloadId; page.file_missing_time = base::Time::Now(); page.digest = kTestDigest;
diff --git a/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc b/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc index 68c618c1..2c0a49f45 100644 --- a/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc +++ b/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc
@@ -42,7 +42,8 @@ TEST_F(CleanupThumbnailsTaskTest, DbConnectionIsNull) { base::MockCallback<StoreThumbnailTask::CompleteCallback> callback; EXPECT_CALL(callback, Run(false)).Times(1); - store()->SetStateForTesting(StoreState::FAILED_LOADING, true); + store()->SetInitializationStatusForTesting( + SqlStoreBase::InitializationStatus::kFailure, true); RunTask(std::make_unique<CleanupThumbnailsTask>( store(), store_utils::FromDatabaseTime(1000), callback.Get())); }
diff --git a/components/offline_pages/core/model/delete_page_task.cc b/components/offline_pages/core/model/delete_page_task.cc index 4784e4d..159bed38 100644 --- a/components/offline_pages/core/model/delete_page_task.cc +++ b/components/offline_pages/core/model/delete_page_task.cc
@@ -4,6 +4,8 @@ #include "components/offline_pages/core/model/delete_page_task.h" +#include <iterator> + #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -41,14 +43,18 @@ // in the SQL query and the result of it can be simply fetched by calling // statement.Column*(INFO_WRAPPER_COUNT), as it's the last column. For example, // please take a look at GetCachedDeletedPageInfoWrappersByUrlPredicateSync. -#define INFO_WRAPPER_FIELDS \ - "offline_id, system_download_id, client_namespace, client_id, file_path, " \ - "request_origin, access_count, creation_time, online_url" -#define INFO_WRAPPER_FIELD_COUNT 8 +#define INFO_WRAPPER_FIELDS \ + "offline_id,system_download_id,client_namespace,client_id,file_path," \ + "request_origin,access_count,creation_time,online_url,original_url" +#define INFO_WRAPPER_FIELD_COUNT 10 struct DeletedPageInfoWrapper { - DeletedPageInfoWrapper(); - DeletedPageInfoWrapper(const DeletedPageInfoWrapper& other); + DeletedPageInfoWrapper() = default; + // Move-only to avoid copies. + DeletedPageInfoWrapper(const DeletedPageInfoWrapper& other) = delete; + DeletedPageInfoWrapper(DeletedPageInfoWrapper&& other) = default; + DeletedPageInfoWrapper& operator=(DeletedPageInfoWrapper&& other) = default; + int64_t offline_id; int64_t system_download_id; ClientId client_id; @@ -58,8 +64,22 @@ int access_count; base::Time creation_time; GURL url; + GURL original_url_if_different; }; +// Consumes |wrapper| and returns an |OfflinePageModel::DeletePageInfo|. +OfflinePageModel::DeletedPageInfo ExtractPageInfo( + DeletedPageInfoWrapper&& wrapper) { + OfflinePageModel::DeletedPageInfo info; + info.offline_id = wrapper.offline_id; + info.system_download_id = wrapper.system_download_id; + info.client_id = std::move(wrapper.client_id); + info.request_origin = std::move(wrapper.request_origin); + info.url = std::move(wrapper.url); + info.original_url_if_different = std::move(wrapper.original_url_if_different); + return info; +} + DeletedPageInfoWrapper CreateInfoWrapper(const sql::Statement& statement) { DeletedPageInfoWrapper info_wrapper; info_wrapper.offline_id = statement.ColumnInt64(0); @@ -73,13 +93,10 @@ info_wrapper.creation_time = store_utils::FromDatabaseTime(statement.ColumnInt64(7)); info_wrapper.url = GURL(statement.ColumnString(8)); + info_wrapper.original_url_if_different = GURL(statement.ColumnString(9)); return info_wrapper; } -DeletedPageInfoWrapper::DeletedPageInfoWrapper() = default; -DeletedPageInfoWrapper::DeletedPageInfoWrapper( - const DeletedPageInfoWrapper& other) = default; - void ReportDeletePageHistograms( const std::vector<DeletedPageInfoWrapper>& info_wrappers) { const int max_minutes = base::TimeDelta::FromDays(365).InMinutes(); @@ -121,7 +138,7 @@ // file is deleted successfully, there will be no such issue. DeletePageTaskResult DeletePagesByDeletedPageInfoWrappersSync( sql::Database* db, - const std::vector<DeletedPageInfoWrapper>& info_wrappers) { + std::vector<DeletedPageInfoWrapper> info_wrappers) { std::vector<OfflinePageModel::DeletedPageInfo> deleted_page_infos; // If there's no page to delete, return an empty list with SUCCESS. @@ -131,14 +148,11 @@ ReportDeletePageHistograms(info_wrappers); bool any_archive_deleted = false; - for (const auto& info_wrapper : info_wrappers) { + for (auto& info_wrapper : info_wrappers) { if (DeleteArchiveSync(info_wrapper.file_path)) { any_archive_deleted = true; if (DeletePageEntryByOfflineIdSync(db, info_wrapper.offline_id)) { - deleted_page_infos.emplace_back( - info_wrapper.offline_id, info_wrapper.system_download_id, - info_wrapper.client_id, info_wrapper.request_origin, - info_wrapper.url); + deleted_page_infos.push_back(ExtractPageInfo(std::move(info_wrapper))); } } } @@ -185,10 +199,10 @@ for (int64_t offline_id : offline_ids) { DeletedPageInfoWrapper info; if (GetDeletedPageInfoWrapperByOfflineIdSync(db, offline_id, &info)) - infos.push_back(info); + infos.push_back(std::move(info)); } DeletePageTaskResult result = - DeletePagesByDeletedPageInfoWrappersSync(db, infos); + DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos)); if (!transaction.Commit()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); @@ -231,11 +245,12 @@ for (ClientId client_id : client_ids) { std::vector<DeletedPageInfoWrapper> temp_infos = GetDeletedPageInfoWrappersByClientIdSync(db, client_id); - infos.insert(infos.end(), temp_infos.begin(), temp_infos.end()); + infos.insert(infos.end(), std::make_move_iterator(temp_infos.begin()), + std::make_move_iterator(temp_infos.end())); } DeletePageTaskResult result = - DeletePagesByDeletedPageInfoWrappersSync(db, infos); + DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos)); if (!transaction.Commit()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); @@ -282,11 +297,12 @@ std::vector<DeletedPageInfoWrapper> temp_infos = GetDeletedPageInfoWrappersByClientIdAndOriginSync(db, client_id, origin); - infos.insert(infos.end(), temp_infos.begin(), temp_infos.end()); + infos.insert(infos.end(), std::make_move_iterator(temp_infos.begin()), + std::make_move_iterator(temp_infos.end())); } DeletePageTaskResult result = - DeletePagesByDeletedPageInfoWrappersSync(db, infos); + DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos)); if (!transaction.Commit()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); @@ -315,7 +331,7 @@ GURL(statement.ColumnString(INFO_WRAPPER_FIELD_COUNT)))) continue; DeletedPageInfoWrapper info_wrapper = CreateInfoWrapper(statement); - info_wrappers.push_back(info_wrapper); + info_wrappers.push_back(std::move(info_wrapper)); } } return info_wrappers; @@ -331,11 +347,11 @@ if (!transaction.Begin()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); - const std::vector<DeletedPageInfoWrapper>& infos = + std::vector<DeletedPageInfoWrapper> infos = GetCachedDeletedPageInfoWrappersByUrlPredicateSync(db, namespaces, predicate); DeletePageTaskResult result = - DeletePagesByDeletedPageInfoWrappersSync(db, infos); + DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos)); if (!transaction.Commit()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); @@ -363,7 +379,7 @@ while (statement.Step()) { DeletedPageInfoWrapper info_wrapper = CreateInfoWrapper(statement); - info_wrappers.push_back(info_wrapper); + info_wrappers.push_back(std::move(info_wrapper)); } // Since the page information was selected by ascending order of last access @@ -389,11 +405,11 @@ if (!transaction.Begin()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {}); - const std::vector<DeletedPageInfoWrapper>& infos = + std::vector<DeletedPageInfoWrapper> infos = GetDeletedPageInfoWrappersForPageLimitDeletion(db, url, name_space, limit); DeletePageTaskResult result = - DeletePagesByDeletedPageInfoWrappersSync(db, infos); + DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos)); if (!transaction.Commit()) return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
diff --git a/components/offline_pages/core/model/delete_page_task_unittest.cc b/components/offline_pages/core/model/delete_page_task_unittest.cc index 90bc107..09a787a3 100644 --- a/components/offline_pages/core/model/delete_page_task_unittest.cc +++ b/components/offline_pages/core/model/delete_page_task_unittest.cc
@@ -35,6 +35,10 @@ const int64_t kTestOfflineIdNoMatch = 20170905LL; const ClientId kTestClientIdNoMatch(kTestNamespace, "20170905"); +GURL OriginalUrl() { + return GURL("http://original.com"); +} + } // namespace class DeletePageTaskTest : public ModelTaskTestBase { @@ -93,6 +97,36 @@ return !base::PathExists(page.file_path) && !stored_page; } +// Delete a page and verify all the information in DeletedPageInfo is accurate. +TEST_F(DeletePageTaskTest, DeletedPageInfoIsPopulated) { + generator()->SetNamespace(kTestNamespace); + OfflinePageItem page1 = generator()->CreateItemWithTempFile(); + page1.url = kTestUrl1; + page1.original_url_if_different = OriginalUrl(); + page1.request_origin = "test-origin"; + page1.system_download_id = 1234; + store_test_util()->InsertItem(page1); + + // Run DeletePageTask for to delete the page. + std::vector<int64_t> offline_ids({page1.offline_id}); + auto task = DeletePageTask::CreateTaskMatchingOfflineIds( + store(), delete_page_callback(), offline_ids); + RunTask(std::move(task)); + + EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result()); + EXPECT_EQ(1UL, last_deleted_page_infos().size()); + + // Verify original_url is returned via DeletedPageInfo. + const DeletedPageInfo& info = last_deleted_page_infos()[0]; + EXPECT_EQ(page1.url, info.url); + EXPECT_EQ(page1.client_id, info.client_id); + EXPECT_EQ(page1.request_origin, info.request_origin); + EXPECT_EQ(page1.system_download_id, info.system_download_id); + EXPECT_EQ(page1.offline_id, info.offline_id); + EXPECT_EQ(OriginalUrl(), info.original_url_if_different); + EXPECT_EQ(OriginalUrl(), info.GetOriginalUrl()); +} + TEST_F(DeletePageTaskTest, DeletePageByOfflineId) { // Add 3 pages and try to delete 2 of them using offline id. generator()->SetNamespace(kTestNamespace);
diff --git a/components/offline_pages/core/model/get_pages_task.cc b/components/offline_pages/core/model/get_pages_task.cc index 0d47018ba..61325c5 100644 --- a/components/offline_pages/core/model/get_pages_task.cc +++ b/components/offline_pages/core/model/get_pages_task.cc
@@ -54,7 +54,7 @@ item.last_access_time = last_access_time; item.access_count = access_count; item.title = title; - item.original_url = original_url; + item.original_url_if_different = original_url; item.request_origin = request_origin; item.system_download_id = system_download_id; item.file_missing_time = file_missing_time; @@ -187,8 +187,8 @@ while (statement.Step()) { OfflinePageItem temp_item = MakeOfflinePageItem(&statement); if (temp_item.url.ReplaceComponents(remove_fragment) == url_to_match || - temp_item.original_url.ReplaceComponents(remove_fragment) == - url_to_match) { + temp_item.original_url_if_different.ReplaceComponents( + remove_fragment) == url_to_match) { result.pages.push_back(temp_item); } }
diff --git a/components/offline_pages/core/model/get_thumbnail_task_unittest.cc b/components/offline_pages/core/model/get_thumbnail_task_unittest.cc index 448f7226..a546dff8 100644 --- a/components/offline_pages/core/model/get_thumbnail_task_unittest.cc +++ b/components/offline_pages/core/model/get_thumbnail_task_unittest.cc
@@ -91,7 +91,8 @@ called = true; EXPECT_FALSE(result); }); - store()->SetStateForTesting(StoreState::FAILED_LOADING, true); + store()->SetInitializationStatusForTesting( + SqlStoreBase::InitializationStatus::kFailure, true); RunTask(std::make_unique<GetThumbnailTask>(store(), 1, std::move(callback)));
diff --git a/components/offline_pages/core/model/has_thumbnail_task_unittest.cc b/components/offline_pages/core/model/has_thumbnail_task_unittest.cc index f7fe69a..0684225ba 100644 --- a/components/offline_pages/core/model/has_thumbnail_task_unittest.cc +++ b/components/offline_pages/core/model/has_thumbnail_task_unittest.cc
@@ -50,7 +50,8 @@ RunTask( std::make_unique<StoreThumbnailTask>(store(), thumb, base::DoNothing())); - store()->SetStateForTesting(StoreState::FAILED_LOADING, true); + store()->SetInitializationStatusForTesting( + SqlStoreBase::InitializationStatus::kFailure, true); base::MockCallback<ThumbnailExistsCallback> exists_callback; EXPECT_CALL(exists_callback, Run(false)); RunTask(std::make_unique<HasThumbnailTask>(store(), thumb.offline_id,
diff --git a/components/offline_pages/core/model/offline_page_item_generator.cc b/components/offline_pages/core/model/offline_page_item_generator.cc index aee905b..619b017b 100644 --- a/components/offline_pages/core/model/offline_page_item_generator.cc +++ b/components/offline_pages/core/model/offline_page_item_generator.cc
@@ -26,7 +26,7 @@ item.client_id.id = id_; item.request_origin = request_origin_; item.url = url_; - item.original_url = original_url_; + item.original_url_if_different = original_url_; item.file_size = file_size_; item.creation_time = creation_time_; item.last_access_time = last_access_time_;
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc index 2e3f29f..9e04bba3 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -517,7 +517,7 @@ // the completion of certain action, i.e., authentication, in the middle. if (skip_clearing_original_url_for_testing_ || save_page_params.original_url != offline_page.url) { - offline_page.original_url = save_page_params.original_url; + offline_page.original_url_if_different = save_page_params.original_url; } if (policy_controller_->IsUserRequestedDownload(
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc index 3f5faa14..a927485 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -378,7 +378,7 @@ EXPECT_EQ(0, saved_page_ptr->access_count); EXPECT_EQ(0, saved_page_ptr->flags); EXPECT_EQ(kTestTitle, saved_page_ptr->title); - EXPECT_EQ(kTestUrl2, saved_page_ptr->original_url); + EXPECT_EQ(kTestUrl2, saved_page_ptr->original_url_if_different); EXPECT_EQ("", saved_page_ptr->request_origin); EXPECT_EQ(kTestDigest, saved_page_ptr->digest); @@ -439,7 +439,7 @@ EXPECT_EQ(kTestUrl, saved_page_ptr->url); // The original URL should be empty. - EXPECT_TRUE(saved_page_ptr->original_url.is_empty()); + EXPECT_TRUE(saved_page_ptr->original_url_if_different.is_empty()); histogram_tester()->ExpectUniqueSample( "OfflinePages.SavePageCount", @@ -479,7 +479,7 @@ EXPECT_EQ(0, saved_page_ptr->access_count); EXPECT_EQ(0, saved_page_ptr->flags); EXPECT_EQ(kTestTitle, saved_page_ptr->title); - EXPECT_EQ(kTestUrl2, saved_page_ptr->original_url); + EXPECT_EQ(kTestUrl2, saved_page_ptr->original_url_if_different); EXPECT_EQ(kTestRequestOrigin, saved_page_ptr->request_origin); histogram_tester()->ExpectUniqueSample(
diff --git a/components/offline_pages/core/model/store_thumbnail_task_unittest.cc b/components/offline_pages/core/model/store_thumbnail_task_unittest.cc index 7dc95df..41527e0a 100644 --- a/components/offline_pages/core/model/store_thumbnail_task_unittest.cc +++ b/components/offline_pages/core/model/store_thumbnail_task_unittest.cc
@@ -69,7 +69,8 @@ } TEST_F(StoreThumbnailTaskTest, DbConnectionIsNull) { - store()->SetStateForTesting(StoreState::FAILED_LOADING, true); + store()->SetInitializationStatusForTesting( + SqlStoreBase::InitializationStatus::kFailure, true); OfflinePageThumbnail thumb; thumb.offline_id = 1; thumb.expiration = store_utils::FromDatabaseTime(1234);
diff --git a/components/offline_pages/core/offline_page_item.cc b/components/offline_pages/core/offline_page_item.cc index e32196f1..09cad91e 100644 --- a/components/offline_pages/core/offline_page_item.cc +++ b/components/offline_pages/core/offline_page_item.cc
@@ -77,7 +77,8 @@ file_size == other.file_size && creation_time == other.creation_time && last_access_time == other.last_access_time && access_count == other.access_count && title == other.title && - flags == other.flags && original_url == other.original_url && + flags == other.flags && + original_url_if_different == other.original_url_if_different && request_origin == other.request_origin && system_download_id == other.system_download_id && file_missing_time == other.file_missing_time &&
diff --git a/components/offline_pages/core/offline_page_item.h b/components/offline_pages/core/offline_page_item.h index dcf7c02..7107e8e 100644 --- a/components/offline_pages/core/offline_page_item.h +++ b/components/offline_pages/core/offline_page_item.h
@@ -49,6 +49,11 @@ bool operator==(const OfflinePageItem& other) const; bool operator<(const OfflinePageItem& other) const; + const GURL& GetOriginalUrl() const { + return original_url_if_different.is_empty() ? url + : original_url_if_different; + } + // The URL of the page. This is the last committed URL. In the case that // redirects occur, access |original_url| for the original URL. GURL url; @@ -76,7 +81,7 @@ Flags flags; // The original URL of the page if not empty. Otherwise, this is set to empty // and |url| should be accessed instead. - GURL original_url; + GURL original_url_if_different; // The app, if any, that the item was saved on behalf of. // Empty string implies Chrome. std::string request_origin;
diff --git a/components/offline_pages/core/offline_page_metadata_store.cc b/components/offline_pages/core/offline_page_metadata_store.cc index 708b6f52..94b3720 100644 --- a/components/offline_pages/core/offline_page_metadata_store.cc +++ b/components/offline_pages/core/offline_page_metadata_store.cc
@@ -4,6 +4,8 @@ #include "components/offline_pages/core/offline_page_metadata_store.h" +#include <utility> + #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -310,177 +312,100 @@ } } -bool PrepareDirectory(const base::FilePath& path) { - base::File::Error error = base::File::FILE_OK; - if (!base::DirectoryExists(path.DirName())) { - if (!base::CreateDirectoryAndGetError(path.DirName(), &error)) { - LOG(ERROR) << "Failed to create offline pages db directory: " - << base::File::ErrorToString(error); - return false; - } +StoreState InitializationStatusToStoreState( + SqlStoreBase::InitializationStatus status) { + switch (status) { + case SqlStoreBase::InitializationStatus::kNotInitialized: + return StoreState::NOT_LOADED; + case SqlStoreBase::InitializationStatus::kInProgress: + return StoreState::INITIALIZING; + case SqlStoreBase::InitializationStatus::kSuccess: + return StoreState::LOADED; + case SqlStoreBase::InitializationStatus::kFailure: + return StoreState::FAILED_LOADING; } - - UMA_HISTOGRAM_ENUMERATION("OfflinePages.SQLStorage.CreateDirectoryResult", - -error, -base::File::FILE_ERROR_MAX); - - return true; -} - -bool InitDatabase(sql::Database* db, - const base::FilePath& path, - bool in_memory) { - db->set_page_size(4096); - db->set_cache_size(500); - db->set_histogram_tag("OfflinePageMetadata"); - db->set_exclusive_locking(); - - if (!in_memory && !PrepareDirectory(path)) - return false; - - bool open_db_result = false; - if (in_memory) - open_db_result = db->OpenInMemory(); - else - open_db_result = db->Open(path); - - if (!open_db_result) { - LOG(ERROR) << "Failed to open database, in memory: " << in_memory; - return false; - } - db->Preload(); - - return CreateSchema(db); -} - -void CloseDatabaseSync( - sql::Database* db, - scoped_refptr<base::SingleThreadTaskRunner> callback_runner, - base::OnceClosure callback) { - if (db) - db->Close(); - callback_runner->PostTask(FROM_HERE, std::move(callback)); } } // anonymous namespace -// static -constexpr base::TimeDelta OfflinePageMetadataStore::kClosingDelay; - OfflinePageMetadataStore::OfflinePageMetadataStore( scoped_refptr<base::SequencedTaskRunner> background_task_runner) - : background_task_runner_(std::move(background_task_runner)), - in_memory_(true), - state_(StoreState::NOT_LOADED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("OfflinePageMetadata", + std::move(background_task_runner), + base::FilePath()) {} OfflinePageMetadataStore::OfflinePageMetadataStore( scoped_refptr<base::SequencedTaskRunner> background_task_runner, const base::FilePath& path) - : background_task_runner_(std::move(background_task_runner)), - in_memory_(false), - db_file_path_(path.AppendASCII("OfflinePages.db")), - state_(StoreState::NOT_LOADED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("OfflinePageMetadata", + std::move(background_task_runner), + path.AppendASCII("OfflinePages.db")) {} -OfflinePageMetadataStore::~OfflinePageMetadataStore() { - if (db_.get() && - !background_task_runner_->DeleteSoon(FROM_HERE, db_.release())) { - DLOG(WARNING) << "SQL database will not be deleted."; - } +OfflinePageMetadataStore::~OfflinePageMetadataStore() = default; + +base::OnceCallback<bool(sql::Database* db)> +OfflinePageMetadataStore::GetSchemaInitializationFunction() { + return base::BindOnce(&CreateSchema); } StoreState OfflinePageMetadataStore::GetStateForTesting() const { - return state_; + return InitializationStatusToStoreState(initialization_status_for_testing()); } -void OfflinePageMetadataStore::SetStateForTesting(StoreState state, - bool reset_db) { - state_ = state; - if (reset_db) - db_.reset(nullptr); -} - -void OfflinePageMetadataStore::InitializeInternal( - base::OnceClosure pending_command) { +void OfflinePageMetadataStore::OnOpenStart(base::TimeTicks last_closing_time) { TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Metadata Store", this, "is reopen", - !last_closing_time_.is_null()); - DCHECK_EQ(state_, StoreState::NOT_LOADED); - - if (!last_closing_time_.is_null()) { + !last_closing_time.is_null()); + if (!last_closing_time.is_null()) { ReportStoreEvent(OfflinePagesStoreEvent::kReopened); UMA_HISTOGRAM_CUSTOM_TIMES("OfflinePages.SQLStorage.TimeFromCloseToOpen", - base::TimeTicks::Now() - last_closing_time_, + base::TimeTicks::Now() - last_closing_time, base::TimeDelta::FromMilliseconds(10), base::TimeDelta::FromMinutes(10), 50 /* buckets */); } else { ReportStoreEvent(OfflinePagesStoreEvent::kOpenedFirstTime); } - - state_ = StoreState::INITIALIZING; - db_.reset(new sql::Database()); - base::PostTaskAndReplyWithResult( - background_task_runner_.get(), FROM_HERE, - base::BindOnce(&InitDatabase, db_.get(), db_file_path_, in_memory_), - base::BindOnce(&OfflinePageMetadataStore::OnInitializeInternalDone, - weak_ptr_factory_.GetWeakPtr(), - std::move(pending_command))); } -void OfflinePageMetadataStore::OnInitializeInternalDone( - base::OnceClosure pending_command, - bool success) { +void OfflinePageMetadataStore::OnOpenDone(bool success) { TRACE_EVENT_ASYNC_STEP_PAST1("offline_pages", "Metadata Store", this, "Initializing", "succeeded", success); - // TODO(fgorski): DCHECK initialization is in progress, once we have a - // relevant value for the store state. - if (success) { - state_ = StoreState::LOADED; - } else { - state_ = StoreState::FAILED_LOADING; - db_.reset(); + if (!success) { TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store", this); } - - CHECK(!pending_command.is_null()); - std::move(pending_command).Run(); - - // Execute other pending commands. - for (auto command_iter = pending_commands_.begin(); - command_iter != pending_commands_.end();) { - std::move(*command_iter++).Run(); - } - - pending_commands_.clear(); - - if (state_ == StoreState::FAILED_LOADING) - state_ = StoreState::NOT_LOADED; } -void OfflinePageMetadataStore::CloseInternal() { - if (state_ != StoreState::LOADED) { +void OfflinePageMetadataStore::OnTaskBegin(bool is_initialized) { + TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Metadata Store: task execution", + this, "is store loaded", is_initialized); +} + +void OfflinePageMetadataStore::OnTaskRunComplete() { + // Note: the time recorded for this trace step will include thread hop wait + // times to the background thread and back. + TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", + "Metadata Store: task execution", this, "Task"); +} + +void OfflinePageMetadataStore::OnTaskReturnComplete() { + TRACE_EVENT_ASYNC_STEP_PAST0( + "offline_pages", "Metadata Store: task execution", this, "Callback"); + TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store: task execution", + this); +} + +void OfflinePageMetadataStore::OnCloseStart( + InitializationStatus status_before_close) { + if (status_before_close != InitializationStatus::kSuccess) { ReportStoreEvent(OfflinePagesStoreEvent::kCloseSkipped); return; } TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Metadata Store", this, "Open"); - last_closing_time_ = base::TimeTicks::Now(); ReportStoreEvent(OfflinePagesStoreEvent::kClosed); - - state_ = StoreState::NOT_LOADED; - background_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &CloseDatabaseSync, db_.get(), base::ThreadTaskRunnerHandle::Get(), - base::BindOnce(&OfflinePageMetadataStore::CloseInternalDone, - weak_ptr_factory_.GetWeakPtr(), std::move(db_)))); } -void OfflinePageMetadataStore::CloseInternalDone( - std::unique_ptr<sql::Database> db) { - db.reset(); +void OfflinePageMetadataStore::OnCloseComplete() { TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Metadata Store", this, "Closing"); TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store", this);
diff --git a/components/offline_pages/core/offline_page_metadata_store.h b/components/offline_pages/core/offline_page_metadata_store.h index e1df0b8..ebfb0d4f 100644 --- a/components/offline_pages/core/offline_page_metadata_store.h +++ b/components/offline_pages/core/offline_page_metadata_store.h
@@ -19,6 +19,7 @@ #include "base/trace_event/trace_event.h" #include "components/offline_pages/core/offline_page_item.h" #include "components/offline_pages/core/offline_store_types.h" +#include "components/offline_pages/task/sql_store_base.h" namespace base { class SequencedTaskRunner; @@ -64,32 +65,8 @@ // |UpgradeFrom54|. // * Upgrade should use |UpgradeWithQuery| and simply specify SQL command to // move data from old table (prefixed by temp_) to the new one. -class OfflinePageMetadataStore { +class OfflinePageMetadataStore : public SqlStoreBase { public: - // This enum is used in an UMA histogram. Hence the entries here shouldn't - // be deleted or re-ordered and new ones should be added to the end. - enum LoadStatus { - LOAD_SUCCEEDED, - STORE_INIT_FAILED, - STORE_LOAD_FAILED, - DATA_PARSING_FAILED, - - // NOTE: always keep this entry at the end. - LOAD_STATUS_COUNT - }; - - typedef base::RepeatingCallback<void(bool /* success */)> ResetCallback; - - // Definition of the callback that is going to run the core of the command in - // the |Execute| method. - template <typename T> - using RunCallback = base::OnceCallback<T(sql::Database*)>; - - // Definition of the callback used to pass the result back to the caller of - // |Execute| method. - template <typename T> - using ResultCallback = base::OnceCallback<void(T)>; - // This is the first version saved in the meta table, which was introduced in // the store in M65. It is set once a legacy upgrade is run successfully for // the last time in |UpgradeFromLegacyVersion|. @@ -97,11 +74,6 @@ static const int kCurrentVersion = 3; static const int kCompatibleVersion = kFirstPostLegacyVersion; - // Defines inactivity time of DB after which it is going to be closed. - // TODO(fgorski): Derive appropriate value in a scientific way. - static constexpr base::TimeDelta kClosingDelay = - base::TimeDelta::FromSeconds(20); - // TODO(fgorski): Move to private and expose ForTest factory. // Applies in PrefetchStore as well. // Creates the store in memory. Should only be used for testing. @@ -113,126 +85,22 @@ scoped_refptr<base::SequencedTaskRunner> background_task_runner, const base::FilePath& database_dir); - ~OfflinePageMetadataStore(); - - // Executes a |run_callback| on SQL store on the blocking thread, and posts - // its result back to calling thread through |result_callback|. - // Calling |Execute| when store is NOT_LOADED will cause the store - // initialization to start. - // Store state needs to be LOADED for |run_callback| to run. - // If initialization fails, |result_callback| is invoked with |default_value|. - template <typename T> - void Execute(RunCallback<T> run_callback, - ResultCallback<T> result_callback, - T default_value) { - // TODO(fgorski): Add a proper state indicating in progress initialization - // and CHECK that state. - - if (state_ == StoreState::NOT_LOADED) { - InitializeInternal(base::BindOnce( - &OfflinePageMetadataStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(), - std::move(run_callback), std::move(result_callback), - std::move(default_value))); - return; - } - - TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Metadata Store: task execution", - this, "is store loaded", - state_ == StoreState::LOADED); - // This if allows to run commands later, after store was given a chance to - // initialize. They would be failing immediately otherwise. - if (state_ == StoreState::INITIALIZING) { - pending_commands_.push_back(base::BindOnce( - &OfflinePageMetadataStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(), - std::move(run_callback), std::move(result_callback), - std::move(default_value))); - TRACE_EVENT_ASYNC_END1("offline_pages", "Metadata Store: task execution", - this, "postponed", true); - return; - } - - // Ensure that any scheduled close operations are canceled. - closing_weak_ptr_factory_.InvalidateWeakPtrs(); - - sql::Database* db = state_ == StoreState::LOADED ? db_.get() : nullptr; - if (!db) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(result_callback), std::move(default_value))); - return; - } - base::PostTaskAndReplyWithResult( - background_task_runner_.get(), FROM_HERE, - base::BindOnce(std::move(run_callback), db), - base::BindOnce(&OfflinePageMetadataStore::RescheduleClosing<T>, - weak_ptr_factory_.GetWeakPtr(), - std::move(result_callback))); - } + ~OfflinePageMetadataStore() override; // Helper function used to force incorrect state for testing purposes. - void SetStateForTesting(StoreState state, bool reset_db); StoreState GetStateForTesting() const; - private: - // Initializes database and calls callback. - void InitializeInternal(base::OnceClosure pending_command); - - // Used to conclude opening/resetting DB connection. - void OnInitializeInternalDone(base::OnceClosure pending_command, - bool success); - - // Reschedules the closing with a delay. Ensures that |result_callback| is - // called. - template <typename T> - void RescheduleClosing(ResultCallback<T> result_callback, T result) { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&OfflinePageMetadataStore::CloseInternal, - closing_weak_ptr_factory_.GetWeakPtr()), - kClosingDelay); - - // Note: the time recorded for this trace step will include thread hop wait - // times to the background thread and back. - TRACE_EVENT_ASYNC_STEP_PAST0( - "offline_pages", "Metadata Store: task execution", this, "Task"); - std::move(result_callback).Run(std::move(result)); - TRACE_EVENT_ASYNC_STEP_PAST0( - "offline_pages", "Metadata Store: task execution", this, "Callback"); - TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store: task execution", - this); - } - - // Internal function initiating the closing. - void CloseInternal(); - - // Completes the closing. Main purpose is to destroy the db pointer. - void CloseInternalDone(std::unique_ptr<sql::Database> db); - - // Background thread where all SQL access should be run. - scoped_refptr<base::SequencedTaskRunner> background_task_runner_; - - // Whether store is opened in memory (for testing) or using a file. - bool in_memory_; - - // Path to the database on disk. - base::FilePath db_file_path_; - - // Database connection. - std::unique_ptr<sql::Database> db_; - - // State of the store. - StoreState state_; - - // Pending commands. - std::vector<base::OnceClosure> pending_commands_; - - // Time of the last time the store was closed. Kept for metrics reporting. - base::TimeTicks last_closing_time_; - - base::WeakPtrFactory<OfflinePageMetadataStore> weak_ptr_factory_; - base::WeakPtrFactory<OfflinePageMetadataStore> closing_weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(OfflinePageMetadataStore); + protected: + // SqlStoreBase: + base::OnceCallback<bool(sql::Database* db)> GetSchemaInitializationFunction() + override; + void OnOpenStart(base::TimeTicks last_open_time) override; + void OnOpenDone(bool success) override; + void OnTaskBegin(bool is_initialized) override; + void OnTaskRunComplete() override; + void OnTaskReturnComplete() override; + void OnCloseStart(InitializationStatus status_before_close) override; + void OnCloseComplete() override; }; } // namespace offline_pages
diff --git a/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/components/offline_pages/core/offline_page_metadata_store_unittest.cc index 4eea0ca..6c3d4dbea 100644 --- a/components/offline_pages/core/offline_page_metadata_store_unittest.cc +++ b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -34,6 +34,7 @@ namespace offline_pages { namespace { +using InitializationStatus = SqlStoreBase::InitializationStatus; #define OFFLINE_PAGES_TABLE_V1 "offlinepages_v1" @@ -390,7 +391,7 @@ statement.BindString(7, item.url.spec()); statement.BindString(8, store_utils::ToDatabaseFilePath(item.file_path)); statement.BindString16(9, item.title); - statement.BindString(10, item.original_url.spec()); + statement.BindString(10, item.original_url_if_different.spec()); statement.BindString(11, item.request_origin); statement.BindInt64(12, item.system_download_id); statement.BindInt(13, store_utils::ToDatabaseTime(item.file_missing_time)); @@ -508,7 +509,7 @@ item.last_access_time = last_access_time; item.access_count = access_count; item.title = title; - item.original_url = original_url; + item.original_url_if_different = original_url; item.request_origin = request_origin; item.system_download_id = system_download_id; item.file_missing_time = file_missing_time; @@ -576,7 +577,7 @@ OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, base::FilePath(kFilePath), kFileSize); offline_page.title = base::UTF8ToUTF16("a title"); - offline_page.original_url = GURL(kOriginalTestURL); + offline_page.original_url_if_different = GURL(kOriginalTestURL); offline_page.system_download_id = kTestSystemDownloadId; offline_page.digest = kTestDigest; @@ -712,7 +713,7 @@ store_utils::ToDatabaseTime(item.last_access_time)); statement.BindInt(8, item.access_count); statement.BindString16(9, item.title); - statement.BindString(10, item.original_url.spec()); + statement.BindString(10, item.original_url_if_different.spec()); statement.BindString(11, item.request_origin); statement.BindInt64(12, item.system_download_id); statement.BindInt64(13, @@ -789,28 +790,28 @@ // Because execute method is self-healing this part of the test expects a // positive results now. - store->SetStateForTesting(StoreState::NOT_LOADED, false); + store->SetInitializationStatusForTesting( + InitializationStatus::kNotInitialized, false); EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - EXPECT_EQ(StoreState::LOADED, store->GetStateForTesting()); + EXPECT_EQ(InitializationStatus::kSuccess, + store->initialization_status_for_testing()); - store->SetStateForTesting(StoreState::FAILED_LOADING, false); + store->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - EXPECT_EQ(StoreState::FAILED_LOADING, store->GetStateForTesting()); + EXPECT_EQ(InitializationStatus::kFailure, + store->initialization_status_for_testing()); - store->SetStateForTesting(StoreState::FAILED_RESET, false); - EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - EXPECT_EQ(StoreState::FAILED_RESET, store->GetStateForTesting()); - - store->SetStateForTesting(StoreState::LOADED, true); + store->SetInitializationStatusForTesting(InitializationStatus::kSuccess, + true); EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - store->SetStateForTesting(StoreState::NOT_LOADED, true); + store->SetInitializationStatusForTesting( + InitializationStatus::kNotInitialized, true); EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - store->SetStateForTesting(StoreState::FAILED_LOADING, false); - EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); - - store->SetStateForTesting(StoreState::FAILED_RESET, false); + store->SetInitializationStatusForTesting(InitializationStatus::kFailure, + false); EXPECT_EQ(0UL, GetOfflinePages(store.get()).size()); } @@ -896,7 +897,7 @@ OfflinePageItem offline_page_2(GURL("https://other.page.com"), 5678LL, kTestClientId2, file_path_2, 12345, OfflineTimeNow(), kTestRequestOrigin); - offline_page_2.original_url = GURL("https://example.com/bar"); + offline_page_2.original_url_if_different = GURL("https://example.com/bar"); offline_page_2.system_download_id = kTestSystemDownloadId; offline_page_2.digest = kTestDigest;
diff --git a/components/offline_pages/core/offline_page_model.h b/components/offline_pages/core/offline_page_model.h index cdd0ded2..8f8b5f5 100644 --- a/components/offline_pages/core/offline_page_model.h +++ b/components/offline_pages/core/offline_page_model.h
@@ -71,6 +71,12 @@ const ClientId& client_id, const std::string& request_origin, const GURL& url); + + const GURL& GetOriginalUrl() const { + return original_url_if_different.is_empty() ? url + : original_url_if_different; + } + // The ID of the deleted page. int64_t offline_id; // The system download manager id of the deleted page. This will be 0 if @@ -82,6 +88,9 @@ std::string request_origin; // URL of the page that was deleted. GURL url; + // Originally request URL of the page that was deleted. If this is empty, + // the final URL is not different than the original URL. + GURL original_url_if_different; }; // Observer of the OfflinePageModel.
diff --git a/components/offline_pages/core/prefetch/prefetch_importer_impl.cc b/components/offline_pages/core/prefetch/prefetch_importer_impl.cc index 069b3a0c..ed0923b 100644 --- a/components/offline_pages/core/prefetch/prefetch_importer_impl.cc +++ b/components/offline_pages/core/prefetch/prefetch_importer_impl.cc
@@ -102,7 +102,7 @@ } OfflinePageItem offline_page(url, archive.offline_id, archive.client_id, dest_path, archive.file_size, base::Time::Now()); - offline_page.original_url = original_url; + offline_page.original_url_if_different = original_url; offline_page.title = archive.title; outstanding_import_offline_ids_.emplace(archive.offline_id);
diff --git a/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc index ab0997e..80baf72c 100644 --- a/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc +++ b/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc
@@ -110,7 +110,8 @@ EXPECT_EQ(kTestOfflineID, offline_page_model()->last_added_page().offline_id); EXPECT_EQ(kTestClientID, offline_page_model()->last_added_page().client_id); EXPECT_EQ(kTestFinalURL, offline_page_model()->last_added_page().url); - EXPECT_EQ(kTestURL, offline_page_model()->last_added_page().original_url); + EXPECT_EQ(kTestURL, + offline_page_model()->last_added_page().original_url_if_different); EXPECT_EQ(kTestTitle, offline_page_model()->last_added_page().title); EXPECT_EQ(kTestFileSize, offline_page_model()->last_added_page().file_size); }
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store.cc b/components/offline_pages/core/prefetch/store/prefetch_store.cc index d28e193d..064e3b65 100644 --- a/components/offline_pages/core/prefetch/store/prefetch_store.cc +++ b/components/offline_pages/core/prefetch/store/prefetch_store.cc
@@ -4,6 +4,8 @@ #include "components/offline_pages/core/prefetch/store/prefetch_store.h" +#include <utility> + #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -23,164 +25,86 @@ const char kPrefetchStoreFileName[] = "PrefetchStore.db"; -bool PrepareDirectory(const base::FilePath& path) { - base::File::Error error = base::File::FILE_OK; - if (!base::DirectoryExists(path.DirName())) { - if (!base::CreateDirectoryAndGetError(path.DirName(), &error)) { - LOG(ERROR) << "Failed to create prefetch db directory: " - << base::File::ErrorToString(error); - return false; - } - } - return true; -} - -// TODO(fgorski): This function and this part of the system in general could -// benefit from a better status code reportable through UMA to better capture -// the reason for failure, aiding the process of repeated attempts to -// open/initialize the database. -bool InitializeSync(sql::Database* db, - const base::FilePath& path, - bool in_memory) { - // These values are default. - db->set_page_size(4096); - db->set_cache_size(500); - db->set_histogram_tag("PrefetchStore"); - db->set_exclusive_locking(); - - if (!in_memory && !PrepareDirectory(path)) - return false; - - bool open_db_result = false; - if (in_memory) - open_db_result = db->OpenInMemory(); - else - open_db_result = db->Open(path); - - if (!open_db_result) { - LOG(ERROR) << "Failed to open database, in memory: " << in_memory; - return false; - } - db->Preload(); - - return PrefetchStoreSchema::CreateOrUpgradeIfNeeded(db); -} - -void CloseDatabaseSync( - sql::Database* db, - scoped_refptr<base::SingleThreadTaskRunner> callback_runner, - base::OnceClosure callback) { - if (db) - db->Close(); - callback_runner->PostTask(FROM_HERE, std::move(callback)); -} - void ReportStoreEvent(OfflinePagesStoreEvent event) { UMA_HISTOGRAM_ENUMERATION("OfflinePages.PrefetchStore.StoreEvent", event); } } // namespace -// static -constexpr base::TimeDelta PrefetchStore::kClosingDelay; - PrefetchStore::PrefetchStore( scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) - : blocking_task_runner_(std::move(blocking_task_runner)), - in_memory_(true), - db_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)), - initialization_status_(InitializationStatus::NOT_INITIALIZED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("PrefetchStore", + std::move(blocking_task_runner), + base::FilePath()) {} PrefetchStore::PrefetchStore( scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, const base::FilePath& path) - : blocking_task_runner_(std::move(blocking_task_runner)), - db_file_path_(path.AppendASCII(kPrefetchStoreFileName)), - in_memory_(false), - db_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)), - initialization_status_(InitializationStatus::NOT_INITIALIZED), - weak_ptr_factory_(this), - closing_weak_ptr_factory_(this) {} + : SqlStoreBase("PrefetchStore", + std::move(blocking_task_runner), + path.AppendASCII(kPrefetchStoreFileName)) {} -PrefetchStore::~PrefetchStore() {} +PrefetchStore::~PrefetchStore() = default; -void PrefetchStore::Initialize(base::OnceClosure pending_command) { +base::OnceCallback<bool(sql::Database* db)> +PrefetchStore::GetSchemaInitializationFunction() { + return base::BindOnce(&PrefetchStoreSchema::CreateOrUpgradeIfNeeded); +} + +void PrefetchStore::OnOpenStart(base::TimeTicks last_closing_time) { TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Prefetch Store", this, "is reopen", - !last_closing_time_.is_null()); - DCHECK_EQ(initialization_status_, InitializationStatus::NOT_INITIALIZED); - initialization_status_ = InitializationStatus::INITIALIZING; - - if (!last_closing_time_.is_null()) { + !last_closing_time.is_null()); + if (!last_closing_time.is_null()) { ReportStoreEvent(OfflinePagesStoreEvent::kReopened); UMA_HISTOGRAM_CUSTOM_TIMES("OfflinePages.PrefetchStore.TimeFromCloseToOpen", - base::TimeTicks::Now() - last_closing_time_, + base::TimeTicks::Now() - last_closing_time, base::TimeDelta::FromMilliseconds(10), base::TimeDelta::FromMinutes(10), 50 /* buckets */); } else { ReportStoreEvent(OfflinePagesStoreEvent::kOpenedFirstTime); } - - // This is how we reset a pointer and provide deleter. This is necessary to - // ensure that we can close the store more than once. - db_ = DatabaseUniquePtr(new sql::Database, - base::OnTaskRunnerDeleter(blocking_task_runner_)); - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&InitializeSync, db_.get(), db_file_path_, in_memory_), - base::BindOnce(&PrefetchStore::OnInitializeDone, - weak_ptr_factory_.GetWeakPtr(), - std::move(pending_command))); } -void PrefetchStore::OnInitializeDone(base::OnceClosure pending_command, - bool success) { +void PrefetchStore::OnOpenDone(bool success) { // TODO(carlosk): Add initializing error reporting here. TRACE_EVENT_ASYNC_STEP_PAST1("offline_pages", "Prefetch Store", this, "Initializing", "succeeded", success); - DCHECK_EQ(initialization_status_, InitializationStatus::INITIALIZING); - if (success) { - initialization_status_ = InitializationStatus::SUCCESS; - } else { - initialization_status_ = InitializationStatus::FAILURE; - db_.reset(); + if (!success) { TRACE_EVENT_ASYNC_END0("offline_pages", "Prefetch Store", this); } - - CHECK(!pending_command.is_null()); - std::move(pending_command).Run(); - - // Once pending commands are empty, we get back to NOT_INITIALIZED state, to - // make it possible to retry initialization next time a DB operation is - // attempted. - if (initialization_status_ == InitializationStatus::FAILURE) - initialization_status_ = InitializationStatus::NOT_INITIALIZED; } -void PrefetchStore::CloseInternal() { - if (initialization_status_ != InitializationStatus::SUCCESS) { +void PrefetchStore::OnTaskBegin(bool is_initialized) { + TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Prefetch Store: task execution", + this, "is store loaded", is_initialized); +} + +void PrefetchStore::OnTaskRunComplete() { + // Note: the time recorded for this trace step will include thread hop wait + // times to the background thread and back. + TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", + "Prefetch Store: task execution", this, "Task"); +} + +void PrefetchStore::OnTaskReturnComplete() { + TRACE_EVENT_ASYNC_STEP_PAST0( + "offline_pages", "Prefetch Store: task execution", this, "Callback"); + TRACE_EVENT_ASYNC_END0("offline_pages", "Prefetch Store: task execution", + this); +} + +void PrefetchStore::OnCloseStart(InitializationStatus initialization_status) { + if (initialization_status != InitializationStatus::kSuccess) { ReportStoreEvent(OfflinePagesStoreEvent::kCloseSkipped); return; } TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Prefetch Store", this, "Open"); - last_closing_time_ = base::TimeTicks::Now(); ReportStoreEvent(OfflinePagesStoreEvent::kClosed); - - initialization_status_ = InitializationStatus::NOT_INITIALIZED; - blocking_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &CloseDatabaseSync, db_.get(), base::ThreadTaskRunnerHandle::Get(), - base::BindOnce(&PrefetchStore::CloseInternalDone, - weak_ptr_factory_.GetWeakPtr(), std::move(db_)))); } -void PrefetchStore::CloseInternalDone(DatabaseUniquePtr db) { - db.reset(); +void PrefetchStore::OnCloseComplete() { TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Prefetch Store", this, "Closing"); TRACE_EVENT_ASYNC_END0("offline_pages", "Prefetch Store", this);
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store.h b/components/offline_pages/core/prefetch/store/prefetch_store.h index b9bcecb..5d80e18 100644 --- a/components/offline_pages/core/prefetch/store/prefetch_store.h +++ b/components/offline_pages/core/prefetch/store/prefetch_store.h
@@ -16,6 +16,7 @@ #include "base/task_runner_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "components/offline_pages/task/sql_store_base.h" namespace sql { class Database; @@ -23,13 +24,6 @@ namespace offline_pages { -enum class InitializationStatus { - NOT_INITIALIZED, - INITIALIZING, - SUCCESS, - FAILURE, -}; - // PrefetchStore is a front end to SQLite store hosting prefetch related // items. // @@ -39,23 +33,8 @@ // // Store has a set of auxiliary functions meant to be used on the blocking // thread. They can be found in prefetch_store_sql_utils file. -class PrefetchStore { +class PrefetchStore : public SqlStoreBase { public: - // Definition of the callback that is going to run the core of the command in - // the |Execute| method. - template <typename T> - using RunCallback = base::OnceCallback<T(sql::Database*)>; - - // Definition of the callback used to pass the result back to the caller of - // |Execute| method. - template <typename T> - using ResultCallback = base::OnceCallback<void(T)>; - - // Defines inactivity time of DB after which it is going to be closed. - // TODO(fgorski): Derive appropriate value in a scientific way. - static constexpr base::TimeDelta kClosingDelay = - base::TimeDelta::FromSeconds(20); - // Creates an instance of |PrefetchStore| with an in-memory SQLite database. explicit PrefetchStore( scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); @@ -65,122 +44,24 @@ PrefetchStore(scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, const base::FilePath& database_dir); - ~PrefetchStore(); - - // Executes a |run_callback| on SQL store on the blocking thread, and posts - // its result back to calling thread through |result_callback|. - // Calling |Execute| when store is NOT_INITIALIZED will cause the store - // initialization to start. - // Store initialization status needs to be SUCCESS for run_callback to run. - // If initialization fails, |result_callback| is invoked with |default_value|. - template <typename T> - void Execute(RunCallback<T> run_callback, - ResultCallback<T> result_callback, - T default_value) { - CHECK_NE(initialization_status_, InitializationStatus::INITIALIZING); - - if (initialization_status_ == InitializationStatus::NOT_INITIALIZED) { - Initialize(base::BindOnce( - &PrefetchStore::Execute<T>, weak_ptr_factory_.GetWeakPtr(), - std::move(run_callback), std::move(result_callback), - std::move(default_value))); - return; - } - - TRACE_EVENT_ASYNC_BEGIN1( - "offline_pages", "Prefetch Store: task execution", this, - "is store loaded", - initialization_status_ == InitializationStatus::SUCCESS); - // Ensure that any scheduled close operations are canceled. - closing_weak_ptr_factory_.InvalidateWeakPtrs(); - - sql::Database* db = initialization_status_ == InitializationStatus::SUCCESS - ? db_.get() - : nullptr; - if (!db) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(result_callback), std::move(default_value))); - } else { - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(std::move(run_callback), db), - base::BindOnce(&PrefetchStore::RescheduleClosing<T>, - weak_ptr_factory_.GetWeakPtr(), - std::move(result_callback))); - } - } - - // Gets the initialization status of the store. - InitializationStatus initialization_status() const { - return initialization_status_; - } + ~PrefetchStore() override; static const char* GetTableCreationSqlForTesting(); + protected: + // SqlStoreBase: + base::OnceCallback<bool(sql::Database* db)> GetSchemaInitializationFunction() + override; + void OnOpenStart(base::TimeTicks last_open_time) override; + void OnOpenDone(bool success) override; + void OnTaskBegin(bool is_initialized) override; + void OnTaskRunComplete() override; + void OnTaskReturnComplete() override; + void OnCloseStart(InitializationStatus status_before_close) override; + void OnCloseComplete() override; + private: friend class PrefetchStoreTestUtil; - - using DatabaseUniquePtr = - std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter>; - - // Used internally to initialize connection. - void Initialize(base::OnceClosure pending_command); - - // Used to conclude opening/resetting DB connection. - void OnInitializeDone(base::OnceClosure pending_command, bool success); - - // Reschedules the closing with a delay. Ensures that |result_callback| is - // called. - template <typename T> - void RescheduleClosing(ResultCallback<T> result_callback, T result) { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&PrefetchStore::CloseInternal, - closing_weak_ptr_factory_.GetWeakPtr()), - kClosingDelay); - - // Note: the time recorded for this trace step will include thread hop wait - // times to the background thread and back. - TRACE_EVENT_ASYNC_STEP_PAST0( - "offline_pages", "Prefetch Store: task execution", this, "Task"); - std::move(result_callback).Run(std::move(result)); - TRACE_EVENT_ASYNC_STEP_PAST0( - "offline_pages", "Prefetch Store: task execution", this, "Callback"); - TRACE_EVENT_ASYNC_END0("offline_pages", "Prefetch Store: task execution", - this); - } - - // Internal function initiating the closing. - void CloseInternal(); - - // Completes the closing. Main purpose is to destroy the db pointer. - void CloseInternalDone(DatabaseUniquePtr db); - - // Background thread where all SQL access should be run. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - - // Path to the database on disk. - base::FilePath db_file_path_; - - // Only open the store in memory. Used for testing. - bool in_memory_; - - // Database connection. - std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter> db_; - - // Initialization status of the store. - InitializationStatus initialization_status_; - - // Time of the last time the store was closed. Kept for metrics reporting. - base::TimeTicks last_closing_time_; - - // Weak pointer to control the callback. - base::WeakPtrFactory<PrefetchStore> weak_ptr_factory_; - // Weak pointer to cancel closing of the store. - base::WeakPtrFactory<PrefetchStore> closing_weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PrefetchStore); }; } // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc index 1f72096..f0247ff 100644 --- a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc +++ b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
@@ -344,7 +344,8 @@ } void PrefetchStoreTestUtil::SimulateInitializationError() { - store_->initialization_status_ = InitializationStatus::FAILURE; + store_->SetInitializationStatusForTesting( + SqlStoreBase::InitializationStatus::kFailure, false); } } // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc b/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc index a44a80c2..fd44031 100644 --- a/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc +++ b/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc
@@ -17,6 +17,8 @@ #include "testing/gtest/include/gtest/gtest.h" namespace offline_pages { +namespace { +using InitializationStatus = SqlStoreBase::InitializationStatus; class PrefetchStoreTest : public testing::Test { public: @@ -88,17 +90,19 @@ PrefetchItem item1( item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST)); EXPECT_TRUE(store_util()->InsertPrefetchItem(item1)); - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); task_runner()->FastForwardBy(PrefetchStore::kClosingDelay); - EXPECT_EQ(InitializationStatus::NOT_INITIALIZED, - store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kNotInitialized, + store()->initialization_status_for_testing()); // Should initialize the store again. PrefetchItem item2( item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST)); EXPECT_TRUE(store_util()->InsertPrefetchItem(item2)); - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); } TEST_F(PrefetchStoreTest, CloseStorePostponed) { @@ -106,30 +110,35 @@ PrefetchItem item1( item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST)); EXPECT_TRUE(store_util()->InsertPrefetchItem(item1)); - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); task_runner()->FastForwardBy(PrefetchStore::kClosingDelay / 2); - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); // Should postpone closing. PrefetchItem item2( item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST)); EXPECT_TRUE(store_util()->InsertPrefetchItem(item2)); - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); // This adds up to more than kClosingDelay after the first call, which means // the closing would trigger, it does not however, since second call caused it // to be postponed. task_runner()->FastForwardBy(2 * PrefetchStore::kClosingDelay / 3); // Store should still be initialized. - EXPECT_EQ(InitializationStatus::SUCCESS, store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kSuccess, + store()->initialization_status_for_testing()); // There is still a pending task to close the store. EXPECT_TRUE(task_runner()->HasPendingTask()); // After this step the store should be closed. task_runner()->FastForwardBy(PrefetchStore::kClosingDelay); - EXPECT_EQ(InitializationStatus::NOT_INITIALIZED, - store()->initialization_status()); + EXPECT_EQ(InitializationStatus::kNotInitialized, + store()->initialization_status_for_testing()); } +} // namespace } // namespace offline_pages
diff --git a/components/offline_pages/task/BUILD.gn b/components/offline_pages/task/BUILD.gn index fa6a891..14e59c2 100644 --- a/components/offline_pages/task/BUILD.gn +++ b/components/offline_pages/task/BUILD.gn
@@ -10,6 +10,8 @@ sources = [ "closure_task.cc", "closure_task.h", + "sql_store_base.cc", + "sql_store_base.h", "task.cc", "task.h", "task_queue.cc", @@ -18,6 +20,7 @@ deps = [ "//base", + "//sql", ] }
diff --git a/components/offline_pages/task/DEPS b/components/offline_pages/task/DEPS new file mode 100644 index 0000000..6fff87d --- /dev/null +++ b/components/offline_pages/task/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+sql", +]
diff --git a/components/offline_pages/task/sql_store_base.cc b/components/offline_pages/task/sql_store_base.cc new file mode 100644 index 0000000..d1552d4 --- /dev/null +++ b/components/offline_pages/task/sql_store_base.cc
@@ -0,0 +1,201 @@ +// Copyright 2019 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/task/sql_store_base.h" + +#include <iterator> +#include <utility> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/sequenced_task_runner.h" +#include "base/trace_event/trace_event.h" + +namespace offline_pages { +namespace { + +bool PrepareDirectory(const base::FilePath& path) { + base::File::Error error = base::File::FILE_OK; + if (!base::DirectoryExists(path.DirName())) { + if (!base::CreateDirectoryAndGetError(path.DirName(), &error)) { + DLOG(ERROR) << "Failed to create prefetch db directory: " + << base::File::ErrorToString(error); + return false; + } + } + return true; +} + +// TODO(fgorski): This function and this part of the system in general could +// benefit from a better status code reportable through UMA to better capture +// the reason for failure, aiding the process of repeated attempts to +// open/initialize the database. +bool InitializeSync( + sql::Database* db, + const base::FilePath& path, + const std::string& histogram_tag, + base::OnceCallback<bool(sql::Database*)> initialize_schema) { + // These values are default. + db->set_page_size(4096); + db->set_cache_size(500); + db->set_histogram_tag(histogram_tag); + db->set_exclusive_locking(); + const bool in_memory = path.empty(); + if (!in_memory && !PrepareDirectory(path)) + return false; + + bool open_db_result = false; + if (in_memory) + open_db_result = db->OpenInMemory(); + else + open_db_result = db->Open(path); + + if (!open_db_result) { + DLOG(ERROR) << "Failed to open database, in memory: " << in_memory; + return false; + } + db->Preload(); + + return std::move(initialize_schema).Run(db); +} + +void CloseDatabaseSync( + sql::Database* db, + scoped_refptr<base::SingleThreadTaskRunner> callback_runner, + base::OnceClosure callback) { + if (db) + db->Close(); + callback_runner->PostTask(FROM_HERE, std::move(callback)); +} + +} // namespace + +// static +constexpr base::TimeDelta SqlStoreBase::kClosingDelay; + +SqlStoreBase::SqlStoreBase( + const std::string& histogram_tag, + scoped_refptr<base::SequencedTaskRunner> background_task_runner, + const base::FilePath& file_path) + : background_task_runner_(background_task_runner), + histogram_tag_(histogram_tag), + db_file_path_(file_path), + db_(nullptr, base::OnTaskRunnerDeleter(background_task_runner_)), + weak_ptr_factory_(this), + closing_weak_ptr_factory_(this) {} + +SqlStoreBase::~SqlStoreBase() = default; + +void SqlStoreBase::SetInitializationStatusForTesting( + InitializationStatus initialization_status, + bool reset_db) { + initialization_status_ = initialization_status; + if (reset_db) + db_.reset(nullptr); +} + +void SqlStoreBase::Initialize(base::OnceClosure pending_command) { + OnOpenStart(last_closing_time_); + + DCHECK_EQ(initialization_status_, InitializationStatus::kNotInitialized); + initialization_status_ = InitializationStatus::kInProgress; + + // This is how we reset a pointer and provide deleter. This is necessary to + // ensure that we can close the store more than once. + db_ = DatabaseUniquePtr(new sql::Database, + base::OnTaskRunnerDeleter(background_task_runner_)); + + base::PostTaskAndReplyWithResult( + background_task_runner_.get(), FROM_HERE, + base::BindOnce(&InitializeSync, db_.get(), db_file_path_, histogram_tag_, + GetSchemaInitializationFunction()), + base::BindOnce(&SqlStoreBase::InitializeDone, + weak_ptr_factory_.GetWeakPtr(), + std::move(pending_command))); +} + +void SqlStoreBase::InitializeDone(base::OnceClosure pending_command, + bool success) { + DCHECK_EQ(initialization_status_, InitializationStatus::kInProgress); + if (success) { + initialization_status_ = InitializationStatus::kSuccess; + } else { + initialization_status_ = InitializationStatus::kFailure; + db_.reset(); + } + + CHECK(!pending_command.is_null()); + std::move(pending_command).Run(); + for (auto command_iter = std::make_move_iterator(pending_commands_.begin()); + command_iter != std::make_move_iterator(pending_commands_.end()); + ++command_iter) { + (*command_iter).Run(); + } + pending_commands_.clear(); + + // Once pending commands are empty, we get back to kNotInitialized state, to + // make it possible to retry initialization next time a DB operation is + // attempted. + if (initialization_status_ == InitializationStatus::kFailure) + initialization_status_ = InitializationStatus::kNotInitialized; + + OnOpenDone(success); +} + +void SqlStoreBase::ExecuteInternal(base::OnceClosure command) { + if (initialization_status_ == InitializationStatus::kInProgress) { + pending_commands_.push_back(std::move(command)); + return; + } + + if (initialization_status_ == InitializationStatus::kNotInitialized) { + Initialize(std::move(command)); + return; + } + + std::move(command).Run(); +} + +sql::Database* SqlStoreBase::ExecuteBegin() { + OnTaskBegin(initialization_status_ == InitializationStatus::kSuccess); + // Ensure that any scheduled close operations are canceled. + closing_weak_ptr_factory_.InvalidateWeakPtrs(); + + return initialization_status_ == InitializationStatus::kSuccess ? db_.get() + : nullptr; +} + +void SqlStoreBase::CloseInternal() { + OnCloseStart(initialization_status_); + + last_closing_time_ = base::TimeTicks::Now(); + + initialization_status_ = InitializationStatus::kNotInitialized; + background_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &CloseDatabaseSync, db_.get(), base::ThreadTaskRunnerHandle::Get(), + base::BindOnce(&SqlStoreBase::CloseInternalDone, + weak_ptr_factory_.GetWeakPtr(), std::move(db_)))); +} + +void SqlStoreBase::RescheduleClosingBefore() { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&SqlStoreBase::CloseInternal, + closing_weak_ptr_factory_.GetWeakPtr()), + kClosingDelay); + + // Note: the time recorded for this trace step will include thread hop wait + // times to the background thread and back. + OnTaskRunComplete(); +} + +void SqlStoreBase::CloseInternalDone(DatabaseUniquePtr db) { + db.reset(); + OnCloseComplete(); +} + +} // namespace offline_pages
diff --git a/components/offline_pages/task/sql_store_base.h b/components/offline_pages/task/sql_store_base.h new file mode 100644 index 0000000..18ea55e --- /dev/null +++ b/components/offline_pages/task/sql_store_base.h
@@ -0,0 +1,190 @@ +// Copyright 2019 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_TASK_SQL_STORE_BASE_H_ +#define COMPONENTS_OFFLINE_PAGES_TASK_SQL_STORE_BASE_H_ + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/location.h" +#include "base/memory/weak_ptr.h" +#include "base/task_runner_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/trace_event/trace_event.h" +#include "sql/database.h" + +namespace offline_pages { + +// Maintains an SQLite database and permits safe access. +// Opens the database only when queried. Automatically closes the database +// if it's not being used. +// This is a base class, and must be overridden to configure the database +// schema. +class SqlStoreBase { + public: + enum class InitializationStatus { + kNotInitialized, + kInProgress, + kSuccess, + kFailure, + }; + + // Definition of the callback that is going to run the core of the command in + // the |Execute| method. + template <typename T> + using RunCallback = base::OnceCallback<T(sql::Database*)>; + + // Definition of the callback used to pass the result back to the caller of + // |Execute| method. + template <typename T> + using ResultCallback = base::OnceCallback<void(T)>; + + // Defines inactivity time of DB after which it is going to be closed. + // TODO(crbug.com/933369): Derive appropriate value in a scientific way. + static constexpr base::TimeDelta kClosingDelay = + base::TimeDelta::FromSeconds(20); + + // If |file_path| is empty, this constructs an in-memory database. + SqlStoreBase(const std::string& histogram_tag, + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, + const base::FilePath& file_path); + virtual ~SqlStoreBase(); + + // Gets the initialization status of the store. + InitializationStatus initialization_status_for_testing() const { + return initialization_status_; + } + + // Executes a |run_callback| on SQL store on the blocking sequence, and posts + // its result back to calling thread through |result_callback|. + // Calling |Execute| when store is kNotInitialized will cause the store + // initialization to start. + // Store initialization status needs to be kSuccess for run_callback to run. + // If initialization fails, |result_callback| is invoked with |default_value|. + template <typename T> + void Execute(RunCallback<T> run_callback, + ResultCallback<T> result_callback, + T default_value) { + ExecuteInternal( + base::BindOnce(&SqlStoreBase::ExecuteAfterInitialized<T>, + weak_ptr_factory_.GetWeakPtr(), std::move(run_callback), + std::move(result_callback), std::move(default_value))); + } + + void SetInitializationStatusForTesting( + InitializationStatus initialization_status, + bool reset_db); + + protected: + // Returns a function that installs the latest schema to |db| (if necessary), + // and returns whether the database was successfully verified to have the + // current schema. |GetSchemaInitializationFunction| is called on the main + // thread, but the returned function is executed on the blocking sequence. + virtual base::OnceCallback<bool(sql::Database* db)> + GetSchemaInitializationFunction() = 0; + + // Optional tracing methods. The derived class may implement tracing events + // with these methods. + + // Called on attempt to open the database. |last_closing_time| is the time + // since the last time the database was closed, or null if the database was + // not previously opened since creation of this. + virtual void OnOpenStart(base::TimeTicks last_closing_time) {} + // Called when done attempting to open the database. + virtual void OnOpenDone(bool success) {} + // Called before a task is executed through |Execute()|. + virtual void OnTaskBegin(bool is_initialized) {} + // Called after calling the |run_callback| in |Execute()|. + virtual void OnTaskRunComplete() {} + // Called after calling the |result_callback| in |Execute()|. + virtual void OnTaskReturnComplete() {} + // Called when starting to close the database. + virtual void OnCloseStart(InitializationStatus status_before_close) {} + // Called after closing the database. + virtual void OnCloseComplete() {} + + private: + using DatabaseUniquePtr = + std::unique_ptr<sql::Database, base::OnTaskRunnerDeleter>; + + void Initialize(base::OnceClosure pending_command); + void InitializeDone(base::OnceClosure pending_command, bool success); + + void ExecuteInternal(base::OnceClosure command); + sql::Database* ExecuteBegin(); + + template <typename T> + void ExecuteAfterInitialized(RunCallback<T> run_callback, + ResultCallback<T> result_callback, + T default_value) { + DCHECK_NE(initialization_status_, InitializationStatus::kNotInitialized); + DCHECK_NE(initialization_status_, InitializationStatus::kInProgress); + sql::Database* db = ExecuteBegin(); + if (!db) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(result_callback), std::move(default_value))); + return; + } + base::PostTaskAndReplyWithResult( + background_task_runner_.get(), FROM_HERE, + base::BindOnce(std::move(run_callback), db), + base::BindOnce(&SqlStoreBase::RescheduleClosing<T>, + weak_ptr_factory_.GetWeakPtr(), + std::move(result_callback))); + } + + // Reschedules the closing with a delay. Ensures that |result_callback| is + // called. + template <typename T> + void RescheduleClosing(ResultCallback<T> result_callback, T result) { + RescheduleClosingBefore(); + std::move(result_callback).Run(std::move(result)); + OnTaskReturnComplete(); + } + + void RescheduleClosingBefore(); + + // Internal function initiating the closing. + void CloseInternal(); + + // Completes the closing. Main purpose is to destroy the db pointer. + void CloseInternalDone(DatabaseUniquePtr db); + + // Background thread where all SQL access should be run. + scoped_refptr<base::SequencedTaskRunner> background_task_runner_; + + // Histogram tag for the sqlite database. + std::string histogram_tag_; + + // Path to the database on disk. If empty, the database is in memory only. + base::FilePath db_file_path_; + + // Database connection. + DatabaseUniquePtr db_; + + // Pending commands. + std::vector<base::OnceClosure> pending_commands_; + + // State of initialization. + InitializationStatus initialization_status_ = + InitializationStatus::kNotInitialized; + + // Time of the last time the store was closed. Kept for metrics reporting. + base::TimeTicks last_closing_time_; + + base::WeakPtrFactory<SqlStoreBase> weak_ptr_factory_; + base::WeakPtrFactory<SqlStoreBase> closing_weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SqlStoreBase); +}; + +} // namespace offline_pages + +#endif // COMPONENTS_OFFLINE_PAGES_TASK_SQL_STORE_BASE_H_
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto index 63c3f350..b896e5d9 100644 --- a/components/optimization_guide/proto/hints.proto +++ b/components/optimization_guide/proto/hints.proto
@@ -7,6 +7,103 @@ package optimization_guide.proto; +// Information about the hint that the client already has for a host. +message MatchedHintInfo { + // Describes the granularity of the key field. + optional KeyRepresentation key_representation = 1; + // The key of the hint currently used for the host. + optional string key = 2; + // The version of the hint for this key already stored on the client. + optional int64 version = 3; +} + +message HostInfo { + // Host that the client is requesting information for. + optional string host = 1; + // Information about the hint that the client already has for the host. + optional MatchedHintInfo matched_hint = 2; +} + +// Request to return a set of hints that guide what optimizations to perform +// on those hosts. +message GetHintsRequest { + // Information about the set of hosts to retrieve hints for. + repeated HostInfo hosts = 1; + + // The set of optimization types that the requesting client can support + // and perform. + // + // It is guaranteed that the response will only contain hints for + // optimizations present in this set. + repeated OptimizationType supported_optimizations = 2; + + // Context in which this request is made. + optional RequestContext context = 3; +} + +// Response to the GetHints request. +message GetHintsResponse { + // An ordered list containing hints for key/optimization combinations. + // + // It is guaranteed that there will only be a single hint per key and key + // representation combination. These hints are intended to apply to a full + // page. It is expected that the client will use the Hint record with the + // most specific key that matches the main frame URL. + // + // Note, this list may contain multiple hints that apply to a page. For + // example, if there are hints for (HOST_SUFFIX,cnn.com) and + // (HOST_SUFFIX,sports.cnn.com), these may both apply to + // sports.cnn.com/foo. In this case, the client is expected to use the + // hints from (HOST_SUFFIX,sports.cnn.com). + repeated Hint hints = 1; + + // The maximum duration in which the hints provided in this response should + // be retained in the client cache. + optional Duration max_cache_duration = 2; + + // A set of hint keys to remove from the client cache. + // + // It is guaranteed that all entries in this list were provided by the client + // in the corresponding request's |hosts.matched_hint| fields. + // + // It is expected for the client to immediately stop using all hints contained + // in this field. Hints that are not present in |hints| or in this field + // should adhere to the client cache's existing expiration policy. + repeated MatchedHintInfo hints_to_remove = 3; +} + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// This is local definition matching server side duration.proto definition. +message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. + optional int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + optional int32 nanos = 2; +} + +// Context in which the hints are requested. +enum RequestContext { + reserved 1; + // Context not specified. + CONTEXT_UNSPECIFIED = 0; + // Requesting hints on page navigation. + CONTEXT_PAGE_NAVIGATION = 2; + // Requesting hints as part of a batch update. + CONTEXT_BATCH_UPDATE = 3; +} + enum OptimizationType { TYPE_UNSPECIFIED = 0; // This optimization blocks JavaScript on the page.
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h index 53a5dee..898adccc 100644 --- a/components/password_manager/core/browser/password_manager_client.h +++ b/components/password_manager/core/browser/password_manager_client.h
@@ -30,7 +30,7 @@ class GURL; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) namespace safe_browsing { class PasswordProtectionService; } @@ -224,7 +224,7 @@ // Returns the current best guess as to the page's display language. virtual std::string GetPageLanguage() const; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) // Return the PasswordProtectionService associated with this instance. virtual safe_browsing::PasswordProtectionService* GetPasswordProtectionService() const = 0;
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.cc b/components/password_manager/core/browser/password_reuse_detection_manager.cc index b5c2f4ddf..342c665 100644 --- a/components/password_manager/core/browser/password_reuse_detection_manager.cc +++ b/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -110,7 +110,7 @@ metrics_util::LogPasswordReuse(password_length, saved_passwords, matching_domains.size(), password_field_detected, reused_password_type); -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) if (reused_password_type == metrics_util::PasswordType::SYNC_PASSWORD) client_->LogPasswordReuseDetectedEvent();
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc index ee3df8f..71bd57c 100644 --- a/components/password_manager/core/browser/stub_password_manager_client.cc +++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -72,7 +72,7 @@ return &log_manager_; } -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) safe_browsing::PasswordProtectionService* StubPasswordManagerClient::GetPasswordProtectionService() const { return nullptr;
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h index 88c5ea4..b2ec574 100644 --- a/components/password_manager/core/browser/stub_password_manager_client.h +++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -51,7 +51,7 @@ const GURL& GetLastCommittedEntryURL() const override; const CredentialsFilter* GetStoreResultFilter() const override; const LogManager* GetLogManager() const override; -#if defined(SAFE_BROWSING_DB_LOCAL) +#if defined(FULL_SAFE_BROWSING) safe_browsing::PasswordProtectionService* GetPasswordProtectionService() const override; void CheckSafeBrowsingReputation(const GURL& form_action,
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 846721a..58d9eaa 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -11089,7 +11089,7 @@ 'name': 'PacHttpsUrlStrippingEnabled', 'type': 'main', 'schema': { 'type': 'boolean' }, - 'supported_on': [ 'chrome.*:52-74', 'chrome_os:52-74' ], + 'supported_on': [ 'chrome.*:52-75', 'chrome_os:52-75' ], 'features': { 'dynamic_refresh': False, 'per_profile': False,
diff --git a/components/previews/content/BUILD.gn b/components/previews/content/BUILD.gn index 8595b0a..fb3f705 100644 --- a/components/previews/content/BUILD.gn +++ b/components/previews/content/BUILD.gn
@@ -9,6 +9,8 @@ "hint_cache_leveldb_store.cc", "hint_cache_leveldb_store.h", "hint_cache_store.h", + "hints_fetcher.cc", + "hints_fetcher.h", "previews_decider_impl.cc", "previews_decider_impl.h", "previews_hints.cc", @@ -17,6 +19,7 @@ "previews_hints_util.h", "previews_optimization_guide.cc", "previews_optimization_guide.h", + "previews_top_host_provider.h", "previews_ui_service.cc", "previews_ui_service.h", "previews_user_data.cc",
diff --git a/components/previews/content/hints_fetcher.cc b/components/previews/content/hints_fetcher.cc new file mode 100644 index 0000000..c6b81fe --- /dev/null +++ b/components/previews/content/hints_fetcher.cc
@@ -0,0 +1,63 @@ +// Copyright 2019 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/previews/content/hints_fetcher.h" + +#include "base/feature_list.h" +#include "base/metrics/histogram_macros.h" +#include "components/optimization_guide/proto/hints.pb.h" +#include "components/previews/content/hint_cache.h" +#include "components/previews/core/previews_experiments.h" + +namespace previews { + +HintsFetcher::HintsFetcher(HintCache* hint_cache) : hint_cache_(hint_cache) {} + +HintsFetcher::~HintsFetcher() {} + +void HintsFetcher::FetchHintsForHosts(const std::vector<std::string>& hosts) { + SEQUENCE_CHECKER(sequence_checker_); + + GetRemoteHints(hosts); +} + +void HintsFetcher::GetRemoteHints(const std::vector<std::string>& hosts) { + get_hints_request_ = + std::make_unique<optimization_guide::proto::GetHintsRequest>(); + + // Add all the optimizations supported by the current version of Chrome, + // regardless of whether the session is in holdback for either of them. + get_hints_request_->add_supported_optimizations( + optimization_guide::proto::NOSCRIPT); + get_hints_request_->add_supported_optimizations( + optimization_guide::proto::RESOURCE_LOADING); + static_assert(static_cast<int>(PreviewsType::LITE_PAGE_REDIRECT) + 1 == + static_cast<int>(PreviewsType::LAST), + "PreviewsType has been updated, make sure OnePlatform hints " + "are not affected"); + + get_hints_request_->set_context( + optimization_guide::proto::CONTEXT_BATCH_UPDATE); + + for (const auto& host : hosts) { + optimization_guide::proto::HostInfo* host_info = + get_hints_request_->add_hosts(); + host_info->set_host(host); + } +} + +void HintsFetcher::HandleResponse(const std::string& config_data, + int status, + int response_code) {} + +void HintsFetcher::OnURLLoadComplete( + std::unique_ptr<std::string> response_body) {} + +bool HintsFetcher::ParseGetHintsResponseAndApplyHints( + const optimization_guide::proto::GetHintsResponse& get_hints_response) { + ALLOW_UNUSED_LOCAL(hint_cache_); + return false; +} + +} // namespace previews
diff --git a/components/previews/content/hints_fetcher.h b/components/previews/content/hints_fetcher.h new file mode 100644 index 0000000..37c4923 --- /dev/null +++ b/components/previews/content/hints_fetcher.h
@@ -0,0 +1,78 @@ +// Copyright 2019 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_PREVIEWS_CONTENT_HINTS_FETCHER_H_ +#define COMPONENTS_PREVIEWS_CONTENT_HINTS_FETCHER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/sequence_checker.h" +#include "components/optimization_guide/proto/hints.pb.h" +#include "components/previews/core/previews_experiments.h" +#include "url/gurl.h" + +namespace previews { + +class HintCache; + +// A class to handle OnePlatform client requests for optimization hints from +// the remote Optimization Guide Service. +// +// When Chrome starts up, if the client's OnePlatform hints have not been +// updated in over day, this class will be triggered to fetch new hints from the +// remote Optimization Guide Service. Owner must ensure that |hint_cache| +// remains alive for the lifetime of |HintsFetcher|. +class HintsFetcher { + public: + explicit HintsFetcher(HintCache* hint_cache); + ~HintsFetcher(); + + // Handles any configuration or checking needed and then + // initiates the fetch of OnePlatform Hints. + void FetchHintsForHosts(const std::vector<std::string>& hosts); + + private: + // Creates the GetHintsResponse proto and executes the SimpleURLLoader request + // to the remote Optimization Guide Service with the |get_hints_request_|. + void GetRemoteHints(const std::vector<std::string>& hosts); + + // Handles the response from the remote Optimization Guide Service. + // |response| is the response body, |status| is the + // |net::Error| of the response, and response_code is the HTTP + // response code (if available). + void HandleResponse(const std::string& response, + int status, + int response_code); + + // URL loader completion callback. + void OnURLLoadComplete(std::unique_ptr<std::string> response_body); + + // Parses the hints component of |get_hints_response| and applies it to + // |hints_|. Returns true if |get_hints_response| was successfully + // parsed and applied. + bool ParseGetHintsResponseAndApplyHints( + const optimization_guide::proto::GetHintsResponse& get_hints_response); + + // Used to hold the GetHintsRequest being constructed and sent as a remote + // request. + std::unique_ptr<optimization_guide::proto::GetHintsRequest> + get_hints_request_; + + // The URL for the remote Optimization Guide Service. + const GURL oneplatform_service_url_; + + // The caller must ensure that the |hints_| outlives this instance. + HintCache* hint_cache_ = nullptr; + + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(HintsFetcher); +}; + +} // namespace previews + +#endif // COMPONENTS_PREVIEWS_CONTENT_HINTS_FETCHER_H_
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc index d5de54e..62109e3 100644 --- a/components/previews/content/previews_decider_impl.cc +++ b/components/previews/content/previews_decider_impl.cc
@@ -184,9 +184,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::Time time = previews_black_list_->AddPreviewNavigation(url, opt_out, type); - if (opt_out) { - last_opt_out_time_ = time; - } LogPreviewNavigation(url, opt_out, type, time, page_id); } @@ -253,29 +250,20 @@ if (url.has_username() || url.has_password()) return PreviewsEligibilityReason::URL_HAS_BASIC_AUTH; - // Trigger the USER_RECENTLY_OPTED_OUT rule when a reload on a preview has - // occurred recently. - if (recent_preview_reload_time_ && - recent_preview_reload_time_.value() + params::SingleOptOutDuration() > - clock_->Now()) { - return PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT; - } + // Skip blacklist checks if the blacklist is ignored. + if (!blacklist_ignored_) { + if (!previews_black_list_) + return PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE; + passed_reasons->push_back(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE); - // In the case that the user has chosen to ignore the normal blacklist rules - // (flags or interventions-internals), a preview should still not be served - // for 5 seconds after the last opt out. This allows "show original" to - // function correctly as the start of that navigation will be within 5 seconds - // (we don't yet re-evaluate on redirects, so this is sufficient). - if (blacklist_ignored_) { - if (clock_->Now() < last_opt_out_time_ + base::TimeDelta::FromSeconds(5)) { + // Trigger the USER_RECENTLY_OPTED_OUT rule when a reload on a preview has + // occurred recently. No need to push_back the eligibility reason as it will + // be added in IsLoadedAndAllowed as the first check. + if (recent_preview_reload_time_ && + recent_preview_reload_time_.value() + params::SingleOptOutDuration() > + clock_->Now()) { return PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT; } - passed_reasons->push_back( - PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT); - } else if (!previews_black_list_) { - return PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE; - } else { - passed_reasons->push_back(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE); // The blacklist will disallow certain hosts for periods of time based on // user's opting out of the preview.
diff --git a/components/previews/content/previews_decider_impl.h b/components/previews/content/previews_decider_impl.h index 89581818..11595db 100644 --- a/components/previews/content/previews_decider_impl.h +++ b/components/previews/content/previews_decider_impl.h
@@ -185,10 +185,6 @@ std::unique_ptr<PreviewsBlackList> previews_black_list_; - // Only used when the blacklist has been disabled to allow "Show Original" to - // function as expected. The time of the most recent opt out event. - base::Time last_opt_out_time_; - // Holds optimization guidance from the server. std::unique_ptr<PreviewsOptimizationGuide> previews_opt_guide_;
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc index 8e811df..169906d 100644 --- a/components/previews/content/previews_decider_impl_unittest.cc +++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -36,6 +36,7 @@ #include "components/blacklist/opt_out_blacklist/opt_out_blacklist_item.h" #include "components/blacklist/opt_out_blacklist/opt_out_store.h" #include "components/optimization_guide/optimization_guide_service.h" +#include "components/previews/content/previews_top_host_provider.h" #include "components/previews/content/previews_ui_service.h" #include "components/previews/content/previews_user_data.h" #include "components/previews/core/previews_black_list.h" @@ -129,6 +130,17 @@ PreviewsEligibilityReason status_; }; +// A test class implementation to enable testing of previews_decider_impl. +class TestPreviewsTopHostProvider : public PreviewsTopHostProvider { + public: + TestPreviewsTopHostProvider() {} + ~TestPreviewsTopHostProvider() override {} + + std::vector<std::string> GetTopHosts(size_t max_sites) const override { + return std::vector<std::string>(); + } +}; + // Stub class of PreviewsOptimizationGuide to control IsWhitelisted and // IsBlacklisted outcomes when testing PreviewsDeciderImpl. class TestPreviewsOptimizationGuide : public PreviewsOptimizationGuide { @@ -136,10 +148,12 @@ TestPreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, - const base::FilePath& test_path) + const base::FilePath& test_path, + PreviewsTopHostProvider* previews_top_host_provider) : PreviewsOptimizationGuide(optimization_guide_service, ui_task_runner, - test_path) {} + test_path, + previews_top_host_provider) {} ~TestPreviewsOptimizationGuide() override {} // PreviewsOptimizationGuide: @@ -383,7 +397,7 @@ std::make_unique<TestPreviewsOptimizationGuide>( &optimization_guide_service_, scoped_task_environment_.GetMainThreadTaskRunner(), - temp_dir_.GetPath()), + temp_dir_.GetPath(), &previews_top_host_provider_), base::BindRepeating(&IsPreviewFieldTrialEnabled), std::make_unique<PreviewsLogger>(), std::move(allowed_types), &network_quality_tracker_)); @@ -416,6 +430,7 @@ base::FieldTrialList field_trial_list_; TestPreviewsDeciderImpl* previews_decider_impl_; optimization_guide::OptimizationGuideService optimization_guide_service_; + TestPreviewsTopHostProvider previews_top_host_provider_; std::unique_ptr<TestPreviewsUIService> ui_service_; network::TestNetworkQualityTracker network_quality_tracker_; }; @@ -1501,7 +1516,7 @@ } } -TEST_F(PreviewsDeciderImplTest, IgnoreFlagStillHasFiveSecondRule) { +TEST_F(PreviewsDeciderImplTest, IgnoreFlagDoesNotCheckBlacklist) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitWithFeatures( {features::kPreviews, features::kClientLoFi}, {}); @@ -1514,21 +1529,10 @@ EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart( &user_data, GURL("https://www.google.com"), false, PreviewsType::LOFI)); - previews_decider_impl()->AddPreviewNavigation( - GURL("http://wwww.somedomain.com"), true, PreviewsType::LOFI, 1); - - EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart( - &user_data, GURL("https://www.google.com"), false, PreviewsType::LOFI)); - EXPECT_EQ(PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT, - ui_service()->decision_reasons().back()); - - clock_.Advance(base::TimeDelta::FromSeconds(6)); + previews_decider_impl()->AddPreviewReload(); EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart( &user_data, GURL("https://www.google.com"), false, PreviewsType::LOFI)); - EXPECT_THAT( - ui_service()->decision_passed_reasons().back(), - ::testing::Contains(PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT)); } TEST_F(PreviewsDeciderImplTest, ReloadsTriggerFiveMinuteRule) {
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc index b9da086..5d0dd359 100644 --- a/components/previews/content/previews_optimization_guide.cc +++ b/components/previews/content/previews_optimization_guide.cc
@@ -8,15 +8,17 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_macros_local.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" #include "components/optimization_guide/hints_component_info.h" #include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/proto/hints.pb.h" #include "components/previews/content/hint_cache_leveldb_store.h" +#include "components/previews/content/hints_fetcher.h" #include "components/previews/content/previews_hints.h" #include "components/previews/content/previews_hints_util.h" +#include "components/previews/content/previews_top_host_provider.h" #include "components/previews/content/previews_user_data.h" #include "components/previews/core/previews_constants.h" #include "components/previews/core/previews_switches.h" @@ -81,7 +83,8 @@ PreviewsOptimizationGuide::PreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, - const base::FilePath& profile_path) + const base::FilePath& profile_path, + PreviewsTopHostProvider* previews_top_host_provider) : optimization_guide_service_(optimization_guide_service), ui_task_runner_(ui_task_runner), background_task_runner_(base::CreateSequencedTaskRunnerWithTraits( @@ -89,6 +92,7 @@ hint_cache_(std::make_unique<HintCache>( std::make_unique<HintCacheLevelDBStore>(profile_path, background_task_runner_))), + previews_top_host_provider_(previews_top_host_provider), ui_weak_ptr_factory_(this) { DCHECK(optimization_guide_service_); hint_cache_->Initialize( @@ -216,6 +220,21 @@ hint_cache_->MaybeCreateComponentUpdateData( base::Version(kManualConfigComponentVersion)))); } + + // If user is eligible for platform hints, currently controlled by a feature + // flag |kPreviewsOnePlatformHints|, start the OnePlatform client request. + // TODO(mcrouse): Add a check for user specific state in addition to the + // feature state: + // (1) Data saver should be enabled + // (2) Infobar notification does not need to be shown to the user. + + if (previews::params::IsOnePlatformHintsEnabled()) { + // TODO(mcrouse): We will likely need to an async call and likely + // within a timer that will call GetOnePlatformClientHints(). + // This is a temporary call for testing. + GetOnePlatformClientHints(); + } + // Register as an observer regardless of hint proto override usage. This is // needed as a signal during testing. optimization_guide_service_->AddObserver(this); @@ -248,6 +267,28 @@ std::move(next_update_closure_))); } +void PreviewsOptimizationGuide::GetOnePlatformClientHints() { + std::vector<std::string> top_hosts = previews_top_host_provider_->GetTopHosts( + previews::params::MaxOnePlatformUpdateHosts()); + DCHECK_GE(previews::params::MaxOnePlatformUpdateHosts(), top_hosts.size()); + + LOCAL_HISTOGRAM_COUNTS_100("Previews.HintsFetcher.GetHintsRequest.HostCount", + top_hosts.size()); + + if (!hintsfetcher_) { + hintsfetcher_ = std::make_unique<HintsFetcher>(hint_cache_.get()); + } + + hintsfetcher_->FetchHintsForHosts(top_hosts); + + // TODO(mcrouse) to build SimpleURLLoader to perform request from service + // for per-user client hints. + // Pass callback for when URLLoader request is successful to call + // PreviewOptimizationGuide::OnOnePlatformClientHintsReceived(). + + OnOnePlatformHintsReceived(); +} + void PreviewsOptimizationGuide::UpdateHints( base::OnceClosure update_closure, std::unique_ptr<PreviewsHints> hints) { @@ -284,4 +325,9 @@ next_update_closure_ = std::move(next_update_closure); } +void PreviewsOptimizationGuide::OnOnePlatformHintsReceived() { + // TODO(mcrouse): Once hints reseponse received from server, will need to + // update the cache and store. +} + } // namespace previews
diff --git a/components/previews/content/previews_optimization_guide.h b/components/previews/content/previews_optimization_guide.h index d001eed..22c6861 100644 --- a/components/previews/content/previews_optimization_guide.h +++ b/components/previews/content/previews_optimization_guide.h
@@ -33,7 +33,9 @@ namespace previews { +class HintsFetcher; class PreviewsHints; +class PreviewsTopHostProvider; class PreviewsUserData; // A Previews optimization guide that makes decisions guided by hints received @@ -42,10 +44,12 @@ : public optimization_guide::OptimizationGuideServiceObserver { public: // The embedder guarantees |optimization_guide_service| outlives |this|. + // The embedder guarantees that |previews_top_host_provider_| outlives |this|. PreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, - const base::FilePath& profile_path); + const base::FilePath& profile_path, + PreviewsTopHostProvider* previews_top_host_provider); ~PreviewsOptimizationGuide() override; @@ -116,6 +120,15 @@ const GURL& document_url, const optimization_guide::proto::Hint* loaded_hint) const; + // Method to request OnePlatform client hints for user's sites with top + // engagement scores and creates a remote request using |hints_fetcher_| On + // request success OnOnePlatformHintsReceived callback will be called. + void GetOnePlatformClientHints(); + + // Called when the response from the OnePlatform Guide Service is handled and + // stored by the |hints_fetcher_|. received. + void OnOnePlatformHintsReceived(); + // The OptimizationGuideService that this guide is listening to. Not owned. optimization_guide::OptimizationGuideService* optimization_guide_service_; @@ -137,6 +150,13 @@ // Used in testing to subscribe to an update event in this class. base::OnceClosure next_update_closure_; + // HintsFetcher handles the request to update Hints from OnePlatform Guide + // Service. + std::unique_ptr<HintsFetcher> hintsfetcher_; + + // TopHostProvider that this guide can query. Not owned. + PreviewsTopHostProvider* previews_top_host_provider_ = nullptr; + // Used to get |weak_ptr_| to self on the UI thread. base::WeakPtrFactory<PreviewsOptimizationGuide> ui_weak_ptr_factory_;
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc index f43f55c7..9cff687 100644 --- a/components/previews/content/previews_optimization_guide_unittest.cc +++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -24,6 +24,7 @@ #include "components/optimization_guide/hints_component_info.h" #include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/proto/hints.pb.h" +#include "components/previews/content/previews_top_host_provider.h" #include "components/previews/content/previews_user_data.h" #include "components/previews/core/bloom_filter.h" #include "components/previews/core/previews_experiments.h" @@ -66,6 +67,17 @@ bool remove_observer_called_; }; +// A test class implementation for unit testing previews_optimization_guide. +class TestPreviewsTopHostProvider : public PreviewsTopHostProvider { + public: + TestPreviewsTopHostProvider() {} + ~TestPreviewsTopHostProvider() override {} + + std::vector<std::string> GetTopHosts(size_t max_sites) const override { + return std::vector<std::string>(); + } +}; + class PreviewsOptimizationGuideTest : public testing::Test { public: PreviewsOptimizationGuideTest() {} @@ -105,7 +117,9 @@ scoped_task_environment_.GetMainThreadTaskRunner()); guide_ = std::make_unique<PreviewsOptimizationGuide>( optimization_guide_service_.get(), - scoped_task_environment_.GetMainThreadTaskRunner(), temp_dir()); + scoped_task_environment_.GetMainThreadTaskRunner(), temp_dir(), + previews_top_host_provider_.get()); + // Add observer is called after the HintCache is fully initialized, // indicating that the PreviewsOptimizationGuide is ready to process hints. while (!optimization_guide_service_->AddObserverCalled()) { @@ -177,6 +191,7 @@ std::unique_ptr<PreviewsOptimizationGuide> guide_; std::unique_ptr<TestOptimizationGuideService> optimization_guide_service_; + std::unique_ptr<TestPreviewsTopHostProvider> previews_top_host_provider_; // Flag set when the OnLoadOptimizationHints callback runs. This indicates // that MaybeLoadOptimizationHints() has completed its processing.
diff --git a/components/previews/content/previews_top_host_provider.h b/components/previews/content/previews_top_host_provider.h new file mode 100644 index 0000000..d4c20c02 --- /dev/null +++ b/components/previews/content/previews_top_host_provider.h
@@ -0,0 +1,27 @@ +// Copyright 2019 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_PREVIEWS_CONTENT_PREVIEWS_TOP_HOST_PROVIDER_H_ +#define COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_TOP_HOST_PROVIDER_H_ + +#include <string> +#include <vector> + +namespace previews { + +// A class to handle querying for the top hosts for a user. +class PreviewsTopHostProvider { + public: + // Returns a vector of at most |max_sites| top hosts, the order of hosts is + // not guaranteed. + virtual std::vector<std::string> GetTopHosts(size_t max_sites) const = 0; + + protected: + PreviewsTopHostProvider() {} + virtual ~PreviewsTopHostProvider() {} +}; + +} // namespace previews + +#endif // COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_TOP_HOST_PROVIDER_H_
diff --git a/components/previews/core/previews_experiments.cc b/components/previews/core/previews_experiments.cc index b31b9bf..cc909ec 100644 --- a/components/previews/core/previews_experiments.cc +++ b/components/previews/core/previews_experiments.cc
@@ -111,6 +111,11 @@ "max_hosts_in_blacklist", 100); } +size_t MaxOnePlatformUpdateHosts() { + return GetFieldTrialParamByFeatureAsInt(features::kPreviewsOnePlatformHints, + "max_oneplatform_update_hosts", 30); +} + int PerHostBlackListOptOutThreshold() { return GetParamValueAsInt(kClientSidePreviewsFieldTrial, "per_host_opt_out_threshold", 2); @@ -327,6 +332,10 @@ return base::FeatureList::IsEnabled(features::kOptimizationHints); } +bool IsOnePlatformHintsEnabled() { + return base::FeatureList::IsEnabled(features::kPreviewsOnePlatformHints); +} + int NoScriptPreviewsInflationPercent() { // The default value was determined from lab experiment data of whitelisted // URLs. It may be improved once there is enough UKM live experiment data
diff --git a/components/previews/core/previews_experiments.h b/components/previews/core/previews_experiments.h index 406233b08..378e7abd 100644 --- a/components/previews/core/previews_experiments.h +++ b/components/previews/core/previews_experiments.h
@@ -68,6 +68,10 @@ // The maximum number of hosts allowed in the in memory black list. size_t MaxInMemoryHostsInBlackList(); +// The maximum number of hosts requested by the client to the OnePlatform +// Service. +size_t MaxOnePlatformUpdateHosts(); + // The number of recent navigations that were opted out of for a given host that // would trigger that host to be blacklisted. int PerHostBlackListOptOutThreshold(); @@ -167,6 +171,10 @@ // Whether server optimization hints are enabled. bool IsOptimizationHintsEnabled(); +// Returns true if the feature to fetch user-specific hints using +// the OnePlatform API is enabled. +bool IsOnePlatformHintsEnabled(); + // For estimating NoScript data savings, this is the percentage factor to // multiple by the network bytes for inflating the original_bytes count. int NoScriptPreviewsInflationPercent();
diff --git a/components/previews/core/previews_features.cc b/components/previews/core/previews_features.cc index fb9f57c9..4e8ce0e 100644 --- a/components/previews/core/previews_features.cc +++ b/components/previews/core/previews_features.cc
@@ -110,5 +110,9 @@ const base::Feature kPreviewsReloadsAreSoftOptOuts{ "PreviewsReloadsAreSoftOptOuts", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables using the OnePlatform Client Hints requests. +const base::Feature kPreviewsOnePlatformHints{ + "PreviewsOnePlatformHints", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace previews
diff --git a/components/previews/core/previews_features.h b/components/previews/core/previews_features.h index 9a7a266..7da9ed7 100644 --- a/components/previews/core/previews_features.h +++ b/components/previews/core/previews_features.h
@@ -25,6 +25,7 @@ extern const base::Feature kHTTPSServerPreviewsUsingURLLoader; extern const base::Feature kDataSaverLiteModeRebranding; extern const base::Feature kPreviewsReloadsAreSoftOptOuts; +extern const base::Feature kPreviewsOnePlatformHints; } // namespace features } // namespace previews
diff --git a/components/safe_browsing/db/v4_update_protocol_manager.cc b/components/safe_browsing/db/v4_update_protocol_manager.cc index 5067d1f..f4f951b6 100644 --- a/components/safe_browsing/db/v4_update_protocol_manager.cc +++ b/components/safe_browsing/db/v4_update_protocol_manager.cc
@@ -21,6 +21,10 @@ #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" +#if !defined(FULL_SAFE_BROWSING) +#include "base/system/sys_info.h" +#endif + using base::Time; using base::TimeDelta; @@ -78,6 +82,15 @@ // Maximum time, in seconds, to wait for a response to an update request. static const int kV4TimerUpdateWaitSecMax = 15 * 60; // 15 minutes +// The default number of entries, per threat type, in the safe browsing +// database on low end (low RAM) devices. This value is also used as the default +// for GMS Safe Browsing on low end devices. +static const int kLowEndDefaultDBEntryCount = 1 << 10; + +// Malware threat DB coverage drops off too much below 4096 entries, so we use +// this values instead of the default above. +static const int kLowEndMalwareDBEntryCount = 1 << 12; + ChromeClientInfo::SafeBrowsingReportingPopulation GetReportingLevelProtoValue( ExtendedReportingLevel reporting_level) { switch (reporting_level) { @@ -243,6 +256,13 @@ list_update_request->mutable_constraints()->add_supported_compressions(RAW); list_update_request->mutable_constraints()->add_supported_compressions( RICE); + +#if !defined(FULL_SAFE_BROWSING) + if (base::SysInfo::IsLowEndDevice()) { + list_update_request->mutable_constraints()->set_max_database_entries( + GetLowEndDBEntryCount(list_update_request->threat_type())); + } +#endif } if (!extended_reporting_level_callback_.is_null()) { @@ -261,6 +281,15 @@ return req_base64; } +int V4UpdateProtocolManager::GetLowEndDBEntryCount(ThreatType threat_type) { + switch (threat_type) { + case ThreatType::MALWARE_THREAT: + return kLowEndMalwareDBEntryCount; + default: + return kLowEndDefaultDBEntryCount; + } +} + bool V4UpdateProtocolManager::ParseUpdateResponse( const std::string& data, ParsedServerResponse* parsed_server_response) {
diff --git a/components/safe_browsing/db/v4_update_protocol_manager.h b/components/safe_browsing/db/v4_update_protocol_manager.h index dc54a89..b0eba38 100644 --- a/components/safe_browsing/db/v4_update_protocol_manager.h +++ b/components/safe_browsing/db/v4_update_protocol_manager.h
@@ -153,6 +153,10 @@ // Get the next update interval, considering whether we are in backoff. base::TimeDelta GetNextUpdateInterval(bool back_off); + // Returns the entry count to be used for the DB for the threat type. Should + // only be used on low end devices (with very little RAM). + int GetLowEndDBEntryCount(ThreatType threat_type); + // The factory that controls the creation of V4UpdateProtocolManager. // This is used by tests. static V4UpdateProtocolManagerFactory* factory_;
diff --git a/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc b/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc index 55c967e3..07445051 100644 --- a/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc +++ b/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc
@@ -282,8 +282,15 @@ std::string encoded_request_with_minus = pm->GetBase64SerializedUpdateRequestProto(); - EXPECT_EQ("Cg8KCHVuaXR0ZXN0EgMxLjAaGAgBEAIaCmg4eGZZcVk-OlIiBCABIAIoASICCAE=", - encoded_request_with_minus); + + const std::string expected = +#if defined(FULL_SAFE_BROWSING) + "Cg8KCHVuaXR0ZXN0EgMxLjAaGAgBEAIaCmg4eGZZcVk-OlIiBCABIAIoASICCAE="; +#else + "Cg8KCHVuaXR0ZXN0EgMxLjAaGwgBEAIaCmg4eGZZcVk-OlIiBxCAICABIAIoASICCAE="; +#endif + + EXPECT_EQ(expected, encoded_request_with_minus); // TODO(vakh): Add a similar test for underscore for completeness, although // the '-' case is sufficient to prove that we are using URL encoding. @@ -346,7 +353,12 @@ store_state_map_->clear(); (*store_state_map_)[ListIdentifier(LINUX_PLATFORM, URL, MALWARE_THREAT)] = "state"; - std::string base = "Cg8KCHVuaXR0ZXN0EgMxLjAaEwgBEAIaBXN0YXRlIgQgASACKAEiAgg"; + const std::string base = +#if defined(FULL_SAFE_BROWSING) + "Cg8KCHVuaXR0ZXN0EgMxLjAaEwgBEAIaBXN0YXRlIgQgASACKAEiAgg"; +#else + "Cg8KCHVuaXR0ZXN0EgMxLjAaFggBEAIaBXN0YXRlIgcQgCAgASACKAEiAgg"; +#endif std::unique_ptr<V4UpdateProtocolManager> pm_with_off(CreateProtocolManager( std::vector<ListUpdateResponse>({}), false, SBER_LEVEL_OFF));
diff --git a/components/security_state/content/content_utils.cc b/components/security_state/content/content_utils.cc index dfda31fb..55878368 100644 --- a/components/security_state/content/content_utils.cc +++ b/components/security_state/content/content_utils.cc
@@ -64,7 +64,7 @@ if (security_info.security_level == security_state::DANGEROUS && !security_info.scheme_is_cryptographic) { security_style_explanations->summary = - l10n_util::GetStringUTF8(IDS_EDITED_NONSECURE_SUMMARY); + l10n_util::GetStringUTF8(IDS_HTTP_NONSECURE_SUMMARY); if (security_info.insecure_input_events.insecure_field_edited) { security_style_explanations->insecure_explanations.push_back( content::SecurityStyleExplanation(
diff --git a/components/security_state_strings.grdp b/components/security_state_strings.grdp index 75f1f9f..86284919 100644 --- a/components/security_state_strings.grdp +++ b/components/security_state_strings.grdp
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <grit-part> <!-- Strings describing Chrome security policy for DevTools security panel --> - <message name="IDS_EDITED_NONSECURE_SUMMARY" desc="Main summary for an HTTP page where a user has entered data in a form field." translateable="false"> + <message name="IDS_HTTP_NONSECURE_SUMMARY" desc="Main summary for where the site is non-secure HTTP." translateable="false"> This page is insecure (unencrypted HTTP). </message> <message name="IDS_EDITED_NONSECURE" desc="Summary phrase for a security problem where the site is non-secure (HTTP) and user has entered data in a form field." translateable="false">
diff --git a/components/send_tab_to_self/OWNERS b/components/send_tab_to_self/OWNERS index 3f65592..cbbc50e6 100644 --- a/components/send_tab_to_self/OWNERS +++ b/components/send_tab_to_self/OWNERS
@@ -1,7 +1,5 @@ hansberry@chromium.org jeffreycohen@chromium.org sebsg@chromium.org -tgupta@chromium.org -tinazwang@chromium.org # COMPONENT: UI>Browser>Sharing
diff --git a/components/services/heap_profiling/public/cpp/settings.cc b/components/services/heap_profiling/public/cpp/settings.cc index 6a9d01f..9a454a4 100644 --- a/components/services/heap_profiling/public/cpp/settings.cc +++ b/components/services/heap_profiling/public/cpp/settings.cc
@@ -30,10 +30,6 @@ const bool kDefaultInProcessMode = false; bool RecordAllAllocationsForStartup() { - const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); - if (cmdline->HasSwitch(kMemlogSampling)) - return false; - return !base::GetFieldTrialParamByFeatureAsBool( kOOPHeapProfilingFeature, kOOPHeapProfilingFeatureSampling, kDefaultShouldSample);
diff --git a/components/services/heap_profiling/public/cpp/switches.cc b/components/services/heap_profiling/public/cpp/switches.cc index 1e9a82c7..0079282 100644 --- a/components/services/heap_profiling/public/cpp/switches.cc +++ b/components/services/heap_profiling/public/cpp/switches.cc
@@ -18,7 +18,6 @@ const char kMemlogModeRendererSampling[] = "renderer-sampling"; const char kMemlogModeUtilityAndBrowser[] = "utility-and-browser"; const char kMemlogModeUtilitySampling[] = "utility-sampling"; -const char kMemlogSampling[] = "memlog-sampling"; const char kMemlogSamplingRate[] = "memlog-sampling-rate"; const char kMemlogStackMode[] = "memlog-stack-mode"; const char kMemlogStackModeMixed[] = "mixed";
diff --git a/components/services/heap_profiling/public/cpp/switches.h b/components/services/heap_profiling/public/cpp/switches.h index e304ffb9..a61a089f 100644 --- a/components/services/heap_profiling/public/cpp/switches.h +++ b/components/services/heap_profiling/public/cpp/switches.h
@@ -19,7 +19,6 @@ extern const char kMemlogModeRendererSampling[]; extern const char kMemlogModeUtilityAndBrowser[]; extern const char kMemlogModeUtilitySampling[]; -extern const char kMemlogSampling[]; extern const char kMemlogSamplingRate[]; extern const char kMemlogStackMode[]; extern const char kMemlogStackModeMixed[];
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn index c6ea7639..e5dedd5 100644 --- a/components/signin/core/browser/BUILD.gn +++ b/components/signin/core/browser/BUILD.gn
@@ -220,8 +220,6 @@ sources = [ "fake_profile_oauth2_token_service.cc", "fake_profile_oauth2_token_service.h", - "test_image_decoder.cc", - "test_image_decoder.h", # TODO(https://crbug.com/907782): Move list_accounts_test_utils to # //services/identity/public/cpp once FakeGCMS no longer depends on it. @@ -233,10 +231,8 @@ deps = [ "//base/test:test_support", - "//components/image_fetcher/core", "//components/prefs", "//google_apis:test_support", - "//ui/gfx:test_support", ] public_deps = [
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc index 885ab88..a9e42f19 100644 --- a/components/signin/core/browser/account_tracker_service_unittest.cc +++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_task_environment.h" #include "build/build_config.h" +#include "components/image_fetcher/core/fake_image_decoder.h" #include "components/image_fetcher/core/image_data_fetcher.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/scoped_user_pref_update.h" @@ -22,7 +23,6 @@ #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/avatar_icon_util.h" #include "components/signin/core/browser/signin_pref_names.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "google_apis/gaia/fake_oauth2_token_service.h" #include "google_apis/gaia/gaia_oauth_client.h" @@ -356,9 +356,9 @@ account_tracker_->AddObserver(&observer_); account_tracker_->Initialize(&pref_service_, std::move(path)); - account_fetcher_->Initialize(signin_client(), token_service(), - account_tracker_.get(), - std::make_unique<TestImageDecoder>()); + account_fetcher_->Initialize( + signin_client(), token_service(), account_tracker_.get(), + std::make_unique<image_fetcher::FakeImageDecoder>()); if (network_enabled) { account_fetcher_->EnableNetworkFetchesForTest(); }
diff --git a/components/signin/core/browser/oauth2_token_service_delegate_android.cc b/components/signin/core/browser/oauth2_token_service_delegate_android.cc index b242742f..4f1df012 100644 --- a/components/signin/core/browser/oauth2_token_service_delegate_android.cc +++ b/components/signin/core/browser/oauth2_token_service_delegate_android.cc
@@ -485,7 +485,8 @@ const std::string& primary_account_id) { DCHECK_EQ(LOAD_CREDENTIALS_NOT_STARTED, load_credentials_state()); set_load_credentials_state(LOAD_CREDENTIALS_IN_PROGRESS); - if (primary_account_id.empty()) { + if (primary_account_id.empty() && + !base::FeatureList::IsEnabled(signin::kMiceFeature)) { FireRefreshTokensLoaded(); return; }
diff --git a/components/signin/core/browser/signin_manager_unittest.cc b/components/signin/core/browser/signin_manager_unittest.cc index 1751a43d..255182d 100644 --- a/components/signin/core/browser/signin_manager_unittest.cc +++ b/components/signin/core/browser/signin_manager_unittest.cc
@@ -14,17 +14,18 @@ #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "build/build_config.h" +#include "components/image_fetcher/core/fake_image_decoder.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/prefs/testing_pref_service.h" #include "components/signin/core/browser/account_consistency_method.h" +#include "components/signin/core/browser/account_fetcher_service.h" #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/device_id_helper.h" #include "components/signin/core/browser/gaia_cookie_manager_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_pref_names.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "google_apis/gaia/fake_oauth2_token_service_delegate.h" @@ -79,9 +80,9 @@ SigninManagerBase::RegisterProfilePrefs(user_prefs_.registry()); SigninManagerBase::RegisterPrefs(local_state_.registry()); account_tracker_.Initialize(&user_prefs_, base::FilePath()); - account_fetcher_.Initialize(&test_signin_client_, &token_service_, - &account_tracker_, - std::make_unique<TestImageDecoder>()); + account_fetcher_.Initialize( + &test_signin_client_, &token_service_, &account_tracker_, + std::make_unique<image_fetcher::FakeImageDecoder>()); } ~SigninManagerTest() override {
diff --git a/components/signin/core/browser/test_image_decoder.cc b/components/signin/core/browser/test_image_decoder.cc deleted file mode 100644 index 225b413..0000000 --- a/components/signin/core/browser/test_image_decoder.cc +++ /dev/null
@@ -1,23 +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. - -#include "components/signin/core/browser/test_image_decoder.h" - -#include "base/values.h" -#include "build/build_config.h" -#include "components/signin/core/browser/account_tracker_service.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" -#include "ui/gfx/image/image_unittest_util.h" - -TestImageDecoder::TestImageDecoder() = default; - -TestImageDecoder::~TestImageDecoder() = default; - -void TestImageDecoder::DecodeImage( - const std::string& image_data, - const gfx::Size& desired_image_frame_size, - const image_fetcher::ImageDecodedCallback& callback) { - callback.Run(image_data.empty() ? gfx::Image() - : gfx::test::CreateImage(64, 64)); -}
diff --git a/components/signin/core/browser/test_image_decoder.h b/components/signin/core/browser/test_image_decoder.h deleted file mode 100644 index 311099d..0000000 --- a/components/signin/core/browser/test_image_decoder.h +++ /dev/null
@@ -1,35 +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. - -#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_TEST_IMAGE_DECODER_H_ -#define COMPONENTS_SIGNIN_CORE_BROWSER_TEST_IMAGE_DECODER_H_ - -#include <memory> - -#include "base/macros.h" -#include "build/build_config.h" -#include "components/image_fetcher/core/image_decoder.h" -#include "components/signin/core/browser/account_fetcher_service.h" - -// This dummy class implements |image_fetcher::ImageDecoder|, and is passed -// as an argument to |AccountFetcherService::Initialize|. -class TestImageDecoder : public image_fetcher::ImageDecoder { - public: - TestImageDecoder(); - ~TestImageDecoder() override; - - // image_fetcher::Decoder implementation: - - // If |image_data| is non-empty, a blank 64x64 image is passed to callback. - // Otherwise an empty image is passed. - void DecodeImage( - const std::string& image_data, - const gfx::Size& desired_image_frame_size, - const image_fetcher::ImageDecodedCallback& callback) override; - - private: - DISALLOW_COPY_AND_ASSIGN(TestImageDecoder); -}; - -#endif // COMPONENTS_SIGNIN_CORE_BROWSER_TEST_IMAGE_DECODER_H_
diff --git a/components/subresource_filter/content/browser/BUILD.gn b/components/subresource_filter/content/browser/BUILD.gn index 712c2fa..2b7aa3b 100644 --- a/components/subresource_filter/content/browser/BUILD.gn +++ b/components/subresource_filter/content/browser/BUILD.gn
@@ -44,7 +44,6 @@ "//components/safe_browsing/db:database_manager", "//components/safe_browsing/db:util", "//components/subresource_filter/content/common", - "//components/subresource_filter/content/mojom", "//components/subresource_filter/core/browser", "//components/subresource_filter/core/common", "//components/subresource_filter/core/mojom", @@ -56,6 +55,7 @@ "//url", ] public_deps = [ + "//components/subresource_filter/content/mojom", "//third_party/flatbuffers:flatbuffers", "//ui/base", ] @@ -106,7 +106,6 @@ "//components/prefs:test_support", "//components/safe_browsing/db:util", "//components/subresource_filter/content/common", - "//components/subresource_filter/content/mojom", "//components/subresource_filter/core/browser", "//components/subresource_filter/core/browser:test_support", "//components/subresource_filter/core/common", @@ -118,4 +117,7 @@ "//ipc:test_support", "//testing/gtest", ] + public_deps = [ + "//components/subresource_filter/content/mojom", + ] }
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc index f1adf21..9dc92262 100644 --- a/components/sync/driver/data_type_manager_impl.cc +++ b/components/sync/driver/data_type_manager_impl.cc
@@ -100,17 +100,19 @@ } void DataTypeManagerImpl::ReadyForStartChanged(ModelType type) { - const auto& dtc_iter = controllers_->find(type); - if (dtc_iter == controllers_->end()) + if (!UpdateUnreadyTypeError(type)) { + // Nothing changed. return; + } - if (dtc_iter->second->ReadyForStart()) { - ForceReconfiguration(); - } else { + if (data_type_status_table_.GetUnreadyErrorTypes().Has(type)) { model_association_manager_.StopDatatype( type, DISABLE_SYNC, SyncError(FROM_HERE, syncer::SyncError::UNREADY_ERROR, "Data type is unready.", type)); + } else if (last_requested_types_.Has(type)) { + // Only reconfigure if the type is both ready and desired. + ForceReconfiguration(); } } @@ -347,28 +349,36 @@ void DataTypeManagerImpl::UpdateUnreadyTypeErrors( const ModelTypeSet& desired_types) { for (ModelType type : desired_types) { - const auto& iter = controllers_->find(type); - if (iter == controllers_->end()) - continue; - const DataTypeController* dtc = iter->second.get(); - bool unready_status = - data_type_status_table_.GetUnreadyErrorTypes().Has(type); - if (dtc->ReadyForStart() != (unready_status == false)) { - // Adjust data_type_status_table_ if unready state in it doesn't match - // DataTypeController::ReadyForStart(). - if (dtc->ReadyForStart()) { - data_type_status_table_.ResetUnreadyErrorFor(type); - } else { - SyncError error(FROM_HERE, SyncError::UNREADY_ERROR, - "Datatype not ready at config time.", type); - std::map<ModelType, SyncError> errors; - errors[type] = error; - data_type_status_table_.UpdateFailedDataTypes(errors); - } - } + UpdateUnreadyTypeError(type); } } +bool DataTypeManagerImpl::UpdateUnreadyTypeError(ModelType type) { + const auto& iter = controllers_->find(type); + if (iter == controllers_->end()) + return false; + + const DataTypeController* dtc = iter->second.get(); + bool unready_status = + data_type_status_table_.GetUnreadyErrorTypes().Has(type); + if (dtc->ReadyForStart() == (unready_status == false)) + return false; + + // Adjust data_type_status_table_ if unready state in it doesn't match + // DataTypeController::ReadyForStart(). + if (dtc->ReadyForStart()) { + data_type_status_table_.ResetUnreadyErrorFor(type); + } else { + SyncError error(FROM_HERE, SyncError::UNREADY_ERROR, + "Datatype not ready at config time.", type); + std::map<ModelType, SyncError> errors; + errors[type] = error; + data_type_status_table_.UpdateFailedDataTypes(errors); + } + + return true; +} + void DataTypeManagerImpl::ProcessReconfigure() { // This may have been called asynchronously; no-op if it is no longer needed. if (!needs_reconfigure_) {
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h index d4be3742..e39ad589 100644 --- a/components/sync/driver/data_type_manager_impl.h +++ b/components/sync/driver/data_type_manager_impl.h
@@ -141,6 +141,11 @@ // DataTypeController::ReadyForStart(). void UpdateUnreadyTypeErrors(const ModelTypeSet& desired_types); + // Update unready state for |type|, such that data_type_status_table_ matches + // DataTypeController::ReadyForStart(). Returns true if there was an actual + // change. + bool UpdateUnreadyTypeError(ModelType type); + // Post a task to reconfigure when no downloading or association are running. void ProcessReconfigure();
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc index c71f4d0..b9bebb28d 100644 --- a/components/sync/driver/sync_driver_switches.cc +++ b/components/sync/driver/sync_driver_switches.cc
@@ -48,6 +48,8 @@ base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kSyncPseudoUSSApps{"SyncPseudoUSSApps", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kSyncPseudoUSSArcPackage{"SyncPseudoUSSArcPackage", + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kSyncPseudoUSSDictionary{"SyncPseudoUSSDictionary", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kSyncPseudoUSSExtensionSettings{
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h index fc6f979..186a6c27 100644 --- a/components/sync/driver/sync_driver_switches.h +++ b/components/sync/driver/sync_driver_switches.h
@@ -24,6 +24,7 @@ kSyncAllowWalletDataInTransportModeWithCustomPassphrase; extern const base::Feature kSyncPseudoUSSAppList; extern const base::Feature kSyncPseudoUSSApps; +extern const base::Feature kSyncPseudoUSSArcPackage; extern const base::Feature kSyncPseudoUSSDictionary; extern const base::Feature kSyncPseudoUSSExtensionSettings; extern const base::Feature kSyncPseudoUSSExtensions;
diff --git a/components/sync/model/syncable_service.cc b/components/sync/model/syncable_service.cc index d4b33c2d..91ee623 100644 --- a/components/sync/model/syncable_service.cc +++ b/components/sync/model/syncable_service.cc
@@ -4,10 +4,16 @@ #include "components/sync/model/syncable_service.h" +#include <utility> + namespace syncer { SyncableService::SyncableService() {} SyncableService::~SyncableService() {} +void SyncableService::WaitUntilReadyToSync(base::OnceClosure done) { + std::move(done).Run(); +} + } // namespace syncer
diff --git a/components/sync/model/syncable_service.h b/components/sync/model/syncable_service.h index 8baaef1..b7b68cf 100644 --- a/components/sync/model/syncable_service.h +++ b/components/sync/model/syncable_service.h
@@ -43,6 +43,12 @@ // make pptimizations or tradeoffs by type, etc. using StartSyncFlare = base::Callback<void(ModelType)>; + // Allows the SyncableService to delay sync events (all below) until the model + // becomes ready to sync. + // TODO(crbug.com/939329): Make this pure to enforce discussion on all + // subclasses. + virtual void WaitUntilReadyToSync(base::OnceClosure done); + // Informs the service to begin syncing the specified synced datatype |type|. // The service should then merge |initial_sync_data| into it's local data, // calling |sync_processor|'s ProcessSyncChanges as necessary to reconcile the
diff --git a/components/sync/model_impl/syncable_service_based_bridge.cc b/components/sync/model_impl/syncable_service_based_bridge.cc index 6fb89ab1..ef44409 100644 --- a/components/sync/model_impl/syncable_service_based_bridge.cc +++ b/components/sync/model_impl/syncable_service_based_bridge.cc
@@ -319,10 +319,9 @@ return; } - std::move(store_factory_) - .Run(type_, base::BindOnce(&SyncableServiceBasedBridge::OnStoreCreated, - weak_ptr_factory_.GetWeakPtr())); - DCHECK(!store_factory_); + syncable_service_->WaitUntilReadyToSync( + base::BindOnce(&SyncableServiceBasedBridge::OnSyncableServiceReady, + weak_ptr_factory_.GetWeakPtr())); } base::Optional<ModelError> SyncableServiceBasedBridge::MergeSyncData( @@ -456,6 +455,15 @@ other); } +void SyncableServiceBasedBridge::OnSyncableServiceReady() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::move(store_factory_) + .Run(type_, base::BindOnce(&SyncableServiceBasedBridge::OnStoreCreated, + weak_ptr_factory_.GetWeakPtr())); + DCHECK(!store_factory_); +} + void SyncableServiceBasedBridge::OnStoreCreated( const base::Optional<ModelError>& error, std::unique_ptr<ModelTypeStore> store) {
diff --git a/components/sync/model_impl/syncable_service_based_bridge.h b/components/sync/model_impl/syncable_service_based_bridge.h index 1576aab8..6b2ab93 100644 --- a/components/sync/model_impl/syncable_service_based_bridge.h +++ b/components/sync/model_impl/syncable_service_based_bridge.h
@@ -76,6 +76,7 @@ ModelTypeChangeProcessor* other); private: + void OnSyncableServiceReady(); void OnStoreCreated(const base::Optional<ModelError>& error, std::unique_ptr<ModelTypeStore> store); void OnReadAllDataForInit(std::unique_ptr<InMemoryStore> in_memory_store,
diff --git a/components/sync/model_impl/syncable_service_based_bridge_unittest.cc b/components/sync/model_impl/syncable_service_based_bridge_unittest.cc index 54b4fa1..3fa2e26 100644 --- a/components/sync/model_impl/syncable_service_based_bridge_unittest.cc +++ b/components/sync/model_impl/syncable_service_based_bridge_unittest.cc
@@ -30,14 +30,16 @@ namespace syncer { namespace { +using testing::_; using testing::DoAll; using testing::ElementsAre; +using testing::Invoke; using testing::IsEmpty; +using testing::IsNull; using testing::NotNull; using testing::Pair; using testing::Return; using testing::SaveArg; -using testing::_; const ModelType kModelType = PREFERENCES; @@ -65,6 +67,7 @@ class MockSyncableService : public SyncableService { public: + MOCK_METHOD1(WaitUntilReadyToSync, void(base::OnceClosure done)); MOCK_METHOD4( MergeDataAndStartSyncing, SyncMergeResult(ModelType type, @@ -82,6 +85,9 @@ protected: SyncableServiceBasedBridgeTest() : store_(ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) { + ON_CALL(syncable_service_, WaitUntilReadyToSync(_)) + .WillByDefault( + Invoke([](base::OnceClosure done) { std::move(done).Run(); })); ON_CALL(syncable_service_, MergeDataAndStartSyncing(_, _, _, _)) .WillByDefault( [&](ModelType type, const SyncDataList& initial_sync_data, @@ -113,15 +119,18 @@ real_processor_.reset(); } - void StartSyncing() { + syncer::DataTypeActivationRequest GetTestActivationRequest() { syncer::DataTypeActivationRequest request; request.error_handler = mock_error_handler_.Get(); request.cache_guid = "TestCacheGuid"; request.authenticated_account_id = "SomeAccountId"; + return request; + } + void StartSyncing() { base::RunLoop loop; real_processor_->OnSyncStarting( - request, + GetTestActivationRequest(), base::BindLambdaForTesting( [&](std::unique_ptr<syncer::DataTypeActivationResponse> response) { worker_ = std::make_unique<MockModelTypeWorker>( @@ -204,6 +213,38 @@ EXPECT_THAT(GetAllData(), ElementsAre(Pair(kClientTagHash, _))); } +TEST_F(SyncableServiceBasedBridgeTest, ShouldWaitUntilModelReadyToSync) { + base::OnceClosure syncable_service_ready_cb; + ON_CALL(syncable_service_, WaitUntilReadyToSync(_)) + .WillByDefault(Invoke([&](base::OnceClosure done) { + syncable_service_ready_cb = std::move(done); + })); + + EXPECT_CALL(mock_processor_, ModelReadyToSync(_)).Times(0); + EXPECT_CALL(syncable_service_, WaitUntilReadyToSync(_)).Times(0); + EXPECT_CALL(syncable_service_, MergeDataAndStartSyncing(_, _, _, _)).Times(0); + + // Bridge initialization alone, without sync itself starting, should not + // issue calls to the syncable service. + InitializeBridge(); + EXPECT_FALSE(syncable_service_ready_cb); + + // Sync itself starting should wait until the syncable service becomes ready, + // before issuing any other call (e.g. MergeDataAndStartSyncing()). + EXPECT_CALL(syncable_service_, WaitUntilReadyToSync(_)); + real_processor_->OnSyncStarting(GetTestActivationRequest(), + base::DoNothing()); + ASSERT_TRUE(syncable_service_ready_cb); + + // When the SyncableService gets ready, the bridge should propagate this + // information to the processor. + EXPECT_CALL(mock_processor_, ModelReadyToSync(_)); + std::move(syncable_service_ready_cb).Run(); + + // Required to initialize the store. + base::RunLoop().RunUntilIdle(); +} + TEST_F(SyncableServiceBasedBridgeTest, ShouldStopSyncableServiceIfPreviouslyStarted) { InitializeBridge();
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-25.png.sha1 new file mode 100644 index 0000000..ca20a2e --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@ +0f9b558ecaac382f144cae2647579a597152b8a3 \ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-26.png.sha1 new file mode 100644 index 0000000..fb7c2f1 --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_back_enabled.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@ +e5fa46dc5e243ac8f164a8b12a077c0109a25c3e \ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-25.png.sha1 new file mode 100644 index 0000000..1c202ad --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@ +67d5565b078f625bfcc6fa4d951529bd638922b2 \ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-26.png.sha1 new file mode 100644 index 0000000..65ac77f --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_both_disabled.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@ +0dfae90e612afa2537605da7fb73e09fbea6149c \ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-25.png.sha1 new file mode 100644 index 0000000..59a7316 --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@ +a22df8a3582ec5f241ab5b2864cfad7385f4c3f6 \ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-26.png.sha1 new file mode 100644 index 0000000..0e284c0 --- /dev/null +++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNavigationTest.navigation_buttons_forward_enabled.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@ +ed308dcd89ed718b2f4c607f5c8776fa9e3b9c0c \ No newline at end of file
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn index 43efd68..24e6c23 100644 --- a/components/viz/common/BUILD.gn +++ b/components/viz/common/BUILD.gn
@@ -214,7 +214,6 @@ "//gpu/command_buffer/client:gles2_interface", "//gpu/command_buffer/client:raster", "//gpu/command_buffer/client:raster_interface", - "//gpu/config", "//gpu/vulkan:buildflags", "//mojo/public/cpp/system", "//third_party/libyuv", @@ -235,6 +234,10 @@ deps += [ "//ui/base" ] } + if (is_android) { + deps += [ "//gpu/config" ] + } + if (is_chromecast) { defines += [ "IS_CHROMECAST" ] }
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index 8e024e5a..52fe758 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -7,7 +7,10 @@ #include "base/command_line.h" #include "build/build_config.h" #include "components/viz/common/switches.h" -#include "gpu/config/gpu_finch_features.h" + +#if defined(OS_ANDROID) +#include "gpu/config/gpu_finch_features.h" // nogncheck +#endif namespace features {
diff --git a/components/viz/common/skia_helper.cc b/components/viz/common/skia_helper.cc index 2228ca37..f6413733 100644 --- a/components/viz/common/skia_helper.cc +++ b/components/viz/common/skia_helper.cc
@@ -6,6 +6,7 @@ #include "cc/base/math_util.h" #include "third_party/skia/include/effects/SkOverdrawColorFilter.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "third_party/skia/include/gpu/GrContext.h" #include "ui/gfx/skia_util.h" namespace viz {
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index aa0f9661..490ef4e 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -156,16 +156,22 @@ const size_t number_of_textures = (is_i420 ? 3 : 2) + (has_alpha ? 1 : 0); std::vector<ResourceMetadata> metadatas; metadatas.reserve(number_of_textures); + // metadata.size is overridden because it is always the same size for + // all planes. Trust the size in |quad| instead. See + // https://crbug.com/939362 auto y_metadata = skia_renderer->lock_set_for_external_use_->LockResource( quad->y_plane_resource_id()); + y_metadata.size = quad->ya_tex_size; metadatas.push_back(std::move(y_metadata)); auto u_metadata = skia_renderer->lock_set_for_external_use_->LockResource( quad->u_plane_resource_id()); + u_metadata.size = quad->uv_tex_size; metadatas.push_back(std::move(u_metadata)); if (is_i420) { auto v_metadata = skia_renderer->lock_set_for_external_use_->LockResource( quad->v_plane_resource_id()); + v_metadata.size = quad->uv_tex_size; metadatas.push_back(std::move(v_metadata)); } @@ -173,6 +179,7 @@ auto a_metadata = skia_renderer->lock_set_for_external_use_->LockResource( quad->a_plane_resource_id()); + a_metadata.size = quad->ya_tex_size; metadatas.push_back(std::move(a_metadata)); }
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc index 15b40f4..9d726a1 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
@@ -4,6 +4,7 @@ #include "components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h" +#include "components/viz/service/display/overlay_strategy_fullscreen.h" #include "components/viz/service/display/overlay_strategy_single_on_top.h" #include "components/viz/service/display/overlay_strategy_underlay.h" #include "components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h" @@ -19,6 +20,9 @@ ~OverlayCandidateValidatorImpl() override = default; void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + // Added in priority order, most to least desirable. + strategies->push_back(std::make_unique<OverlayStrategyFullscreen>(this)); + strategies->push_back(std::make_unique<OverlayStrategySingleOnTop>(this)); strategies->push_back(std::make_unique<OverlayStrategyUnderlay>( this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates)); }
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc index 7cb357c..b4640f7 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -76,6 +76,13 @@ DCHECK(!added_frame_observer_); } +CompositorFrameSinkSupport::PresentationFeedbackMap +CompositorFrameSinkSupport::TakePresentationFeedbacks() { + PresentationFeedbackMap map; + map.swap(presentation_feedbacks_); + return map; +} + void CompositorFrameSinkSupport::SetUpHitTest( LatestLocalSurfaceIdLookupDelegate* local_surface_id_lookup_delegate) { DCHECK(is_root_);
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h index 28a67051..d62d8a38 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -56,6 +56,8 @@ const gfx::Size& frame_size_in_pixels, const gfx::Rect& damage_rect, base::TimeTicks expected_display_time)>; + using PresentationFeedbackMap = + base::flat_map<uint32_t, gfx::PresentationFeedback>; static const uint64_t kFrameIndexStart = 2; @@ -80,11 +82,12 @@ FrameSinkManagerImpl* frame_sink_manager() { return frame_sink_manager_; } - const base::flat_map<uint32_t, gfx::PresentationFeedback>& - presentation_feedbacks() { + const PresentationFeedbackMap& presentation_feedbacks() { return presentation_feedbacks_; } + PresentationFeedbackMap TakePresentationFeedbacks() WARN_UNUSED_RESULT; + // Viz hit-test setup is only called when |is_root_| is true (except on // android webview). void SetUpHitTest( @@ -304,7 +307,7 @@ bool callback_received_receive_ack_ = true; uint32_t trace_sequence_ = 0; - base::flat_map<uint32_t, gfx::PresentationFeedback> presentation_feedbacks_; + PresentationFeedbackMap presentation_feedbacks_; LocalSurfaceId::ParentComponent last_evicted_parent_component_;
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc index 48f14281..cd0e3c1 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -548,6 +548,8 @@ dirty_rect_, gfx::Vector2d(source_size.width(), source_size.height()), gfx::Vector2d(content_rect.width(), content_rect.height())); update_rect.Offset(content_rect.OffsetFromOrigin()); + if (pixel_format_ == media::PIXEL_FORMAT_I420) + update_rect = ExpandRectToI420SubsampleBoundaries(update_rect); } metadata->SetRect(media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, update_rect); @@ -814,6 +816,16 @@ return result; } +// static +gfx::Rect FrameSinkVideoCapturerImpl::ExpandRectToI420SubsampleBoundaries( + const gfx::Rect& rect) { + const int x = rect.x() & ~1; + const int y = rect.y() & ~1; + const int r = rect.right() + (rect.right() & 1); + const int b = rect.bottom() + (rect.bottom() & 1); + return gfx::Rect(x, y, r - x, b - y); +} + FrameSinkVideoCapturerImpl::CapturedFrame::CapturedFrame( int64_t capture_frame_number, OracleFrameNumber oracle_frame_number,
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h index 15f79e5..3c5ddc07 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
@@ -214,6 +214,10 @@ // I420 format, ensures that every dimension is even and at least 2. gfx::Size AdjustSizeForPixelFormat(const gfx::Size& size); + // Expands |rect| such that its x, y, right, and bottom values are even + // numbers. + static gfx::Rect ExpandRectToI420SubsampleBoundaries(const gfx::Rect& rect); + // Owner/Manager of this instance. FrameSinkVideoCapturerManager* const frame_sink_manager_;
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc index 073681e..68b0214 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -43,6 +43,11 @@ namespace viz { namespace { +bool AlignsWithI420SubsamplingBoundaries(const gfx::Rect& update_rect) { + return (update_rect.x() % 2 == 0) && (update_rect.y() % 2 == 0) && + (update_rect.width() % 2 == 0) && (update_rect.height() % 2 == 0); +} + // Returns true if |frame|'s device scale factor, page scale factor and root // scroll offset are equal to the expected values. bool CompareVarsInCompositorFrameMetadata( @@ -473,6 +478,11 @@ PropagateMojoTasks(); } + gfx::Rect ExpandRectToI420SubsampleBoundaries(const gfx::Rect& rect) { + return FrameSinkVideoCapturerImpl::ExpandRectToI420SubsampleBoundaries( + rect); + } + protected: SizeSet size_set_; scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; @@ -1048,6 +1058,10 @@ size_set().expected_content_rect.height())); expected_frame_update_rect.Offset( size_set().expected_content_rect.OffsetFromOrigin()); + EXPECT_FALSE(AlignsWithI420SubsamplingBoundaries(expected_frame_update_rect)); + expected_frame_update_rect = + ExpandRectToI420SubsampleBoundaries(expected_frame_update_rect); + EXPECT_TRUE(AlignsWithI420SubsamplingBoundaries(expected_frame_update_rect)); // Notify frame damage with custom damage rect, and expect that the refresh // frame is delivered to the consumer with a corresponding |update_rect|.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index d743ffc..e90f38a4 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1274,8 +1274,11 @@ "notifications/notification_id_generator.h", "notifications/notification_storage.cc", "notifications/notification_storage.h", + "notifications/notification_trigger_constants.h", "notifications/platform_notification_context_impl.cc", "notifications/platform_notification_context_impl.h", + "notifications/platform_notification_service_proxy.cc", + "notifications/platform_notification_service_proxy.h", "payments/payment_app_context_impl.cc", "payments/payment_app_context_impl.h", "payments/payment_app_database.cc",
diff --git a/content/browser/accessibility/OWNERS b/content/browser/accessibility/OWNERS index 2c85844e..1ff46368 100644 --- a/content/browser/accessibility/OWNERS +++ b/content/browser/accessibility/OWNERS
@@ -1,4 +1,7 @@ file://ui/accessibility/OWNERS +# For ATK / AuraLinux +mrobinson@igalia.com + # TEAM: chromium-accessibility@chromium.org # COMPONENT: UI>Accessibility
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 6dcefa2a7..962bbcd 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -18,6 +18,7 @@ #include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "content/common/accessibility_messages.h" #include "content/public/common/content_client.h" +#include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_unique_id.h" @@ -1059,6 +1060,15 @@ return *empty_data; } +ui::AXNodePosition::AXPositionInstance +BrowserAccessibility::CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity) const { + DCHECK(manager_); + return ui::AXNodePosition::CreateTextPosition(manager_->ax_tree_id(), GetId(), + offset, affinity); +} + gfx::NativeViewAccessible BrowserAccessibility::GetNSWindow() { NOTREACHED(); return nullptr;
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 0959288..2e0c652 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h
@@ -21,8 +21,10 @@ #include "content/browser/accessibility/browser_accessibility_position.h" #include "content/common/content_export.h" #include "third_party/blink/public/web/web_ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_range.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_platform_node.h" @@ -346,6 +348,10 @@ // AXPlatformNodeDelegate. const ui::AXNodeData& GetData() const override; const ui::AXTreeData& GetTreeData() const override; + ui::AXNodePosition::AXPositionInstance CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity = + ax::mojom::TextAffinity::kDownstream) const override; gfx::NativeViewAccessible GetNSWindow() override; gfx::NativeViewAccessible GetParent() override; int GetChildCount() override;
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index d96a0347..a82025b4 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -16,18 +16,14 @@ #include "content/browser/accessibility/browser_accessibility.h" #include "content/common/accessibility_messages.h" #include "content/public/common/use_zoom_for_dsf_policy.h" +#include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_tree_data.h" +#include "ui/accessibility/ax_tree_manager_map.h" #include "ui/accessibility/ax_tree_serializer.h" namespace content { namespace { - -// Map from AXTreeID to BrowserAccessibilityManager -using AXTreeIDMap = std::map<ui::AXTreeID, BrowserAccessibilityManager*>; -base::LazyInstance<AXTreeIDMap>::Leaky g_ax_tree_id_map = - LAZY_INSTANCE_INITIALIZER; - // A function to call when focus changes, for testing only. base::LazyInstance<base::Closure>::DestructorAtExit g_focus_change_callback_for_testing = LAZY_INSTANCE_INITIALIZER; @@ -148,9 +144,8 @@ // static BrowserAccessibilityManager* BrowserAccessibilityManager::FromID( ui::AXTreeID ax_tree_id) { - AXTreeIDMap& ax_tree_id_map = g_ax_tree_id_map.Get(); - AXTreeIDMap::iterator iter = ax_tree_id_map.find(ax_tree_id); - return iter == ax_tree_id_map.end() ? nullptr : iter->second; + return static_cast<BrowserAccessibilityManager*>( + ui::AXTreeManagerMap::GetInstance().GetManager(ax_tree_id)); } BrowserAccessibilityManager::BrowserAccessibilityManager( @@ -191,7 +186,7 @@ BrowserAccessibilityManager::~BrowserAccessibilityManager() { tree_.reset(nullptr); event_generator_.ReleaseTree(); - g_ax_tree_id_map.Get().erase(ax_tree_id_); + ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(ax_tree_id_); } void BrowserAccessibilityManager::Initialize( @@ -1169,9 +1164,9 @@ bool ax_tree_id_changed = false; if (GetTreeData().tree_id != ui::AXTreeIDUnknown() && GetTreeData().tree_id != ax_tree_id_) { - g_ax_tree_id_map.Get().erase(ax_tree_id_); + ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(ax_tree_id_); ax_tree_id_ = GetTreeData().tree_id; - g_ax_tree_id_map.Get().insert(std::make_pair(ax_tree_id_, this)); + ui::AXTreeManagerMap::GetInstance().AddTreeManager(ax_tree_id_, this); ax_tree_id_changed = true; } @@ -1189,6 +1184,19 @@ } } +ui::AXNode* BrowserAccessibilityManager::GetNodeFromTree(ui::AXTreeID tree_id, + int32_t node_id) { + auto* manager = BrowserAccessibilityManager::FromID(tree_id); + if (!manager) + return nullptr; + + BrowserAccessibility* wrapper = manager->GetFromID(node_id); + if (wrapper) + return wrapper->node(); + + return nullptr; +} + BrowserAccessibilityManager* BrowserAccessibilityManager::GetRootManager() { BrowserAccessibility* parent = GetParentNodeFromParentTree(); if (!parent)
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index 6dc23ac..0a2c167 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -26,6 +26,7 @@ #include "ui/accessibility/ax_range.h" #include "ui/accessibility/ax_serializable_tree.h" #include "ui/accessibility/ax_tree_id_registry.h" +#include "ui/accessibility/ax_tree_manager.h" #include "ui/accessibility/ax_tree_observer.h" #include "ui/accessibility/ax_tree_update.h" #include "ui/gfx/native_widget_types.h" @@ -112,7 +113,8 @@ }; // Manages a tree of BrowserAccessibility objects. -class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeObserver { +class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeObserver, + public ui::AXTreeManager { protected: using BrowserAccessibilityPositionInstance = BrowserAccessibilityPosition::AXPositionInstance; @@ -361,6 +363,9 @@ bool root_changed, const std::vector<ui::AXTreeObserver::Change>& changes) override; + // AXTreeManager implementation. + ui::AXNode* GetNodeFromTree(ui::AXTreeID tree_id, int32_t node_id) override; + BrowserAccessibilityDelegate* delegate() const { return delegate_; } // If this BrowserAccessibilityManager is a child frame or guest frame,
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc index 01dff2c9..c5c088d6 100644 --- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc +++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -132,9 +132,8 @@ return false; } -// Marked flaky per http://crbug.com/101984 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, - DISABLED_WebpageAccessibility) { + WebpageAccessibility) { // Create a data url and load it. const char url_str[] = "data:text/html," @@ -161,7 +160,7 @@ // Check properties of the BODY element. ASSERT_EQ(1, root->child_count()); const ui::AXNode* body = root->ChildAtIndex(0); - EXPECT_EQ(ax::mojom::Role::kGroup, body->data().role); + EXPECT_EQ(ax::mojom::Role::kGenericContainer, body->data().role); EXPECT_STREQ("body", GetAttr(body, ax::mojom::StringAttribute::kHtmlTag).c_str()); EXPECT_STREQ("block",
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc index 82db89bb..daf4c948 100644 --- a/content/browser/browsing_instance.cc +++ b/content/browser/browsing_instance.cc
@@ -8,13 +8,19 @@ #include "base/logging.h" #include "content/browser/site_instance_impl.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_or_resource_context.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/site_isolation_policy.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" namespace content { +namespace { +const char* const kDefaultInstanceSiteURL = "http://unisolated.invalid"; +} // namespace + // Start the BrowsingInstance ID counter from 1 to avoid a conflict with the // invalid BrowsingInstanceId value, which is 0 in its underlying IdType32. int BrowsingInstance::next_browsing_instance_id_ = 1; @@ -39,10 +45,17 @@ void BrowsingInstance::SetDefaultProcess(RenderProcessHost* default_process) { DCHECK(!default_process_); + DCHECK(!default_site_instance_); default_process_ = default_process; default_process_->AddObserver(this); } +bool BrowsingInstance::IsDefaultSiteInstance( + const SiteInstanceImpl* site_instance) const { + return site_instance != nullptr && + site_instance == default_site_instance_.get(); +} + bool BrowsingInstance::HasSiteInstance(const GURL& url) { std::string site = SiteInstanceImpl::GetSiteForURL(browser_context_, isolation_context_, url) @@ -52,14 +65,13 @@ } scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURL( - const GURL& url) { - std::string site = - SiteInstanceImpl::GetSiteForURL(browser_context_, isolation_context_, url) - .possibly_invalid_spec(); + const GURL& url, + bool allow_default_instance) { + scoped_refptr<SiteInstanceImpl> site_instance = + GetSiteInstanceForURLHelper(url, allow_default_instance); - auto i = site_instance_map_.find(site); - if (i != site_instance_map_.end()) - return i->second; + if (site_instance) + return site_instance; // No current SiteInstance for this site, so let's create one. scoped_refptr<SiteInstanceImpl> instance = new SiteInstanceImpl(this); @@ -69,10 +81,68 @@ return instance; } +void BrowsingInstance::GetSiteAndLockForURL(const GURL& url, + bool allow_default_instance, + GURL* site_url, + GURL* lock_url) { + scoped_refptr<SiteInstanceImpl> site_instance = + GetSiteInstanceForURLHelper(url, allow_default_instance); + + if (site_instance) { + *site_url = site_instance->GetSiteURL(); + *lock_url = site_instance->lock_url(); + return; + } + + BrowserOrResourceContext context(browser_context_); + *site_url = SiteInstanceImpl::GetSiteForURL( + context, isolation_context_, url, true /* should_use_effective_urls */); + *lock_url = SiteInstanceImpl::DetermineProcessLockURL( + context, isolation_context_, url); +} + +scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURLHelper( + const GURL& url, + bool allow_default_instance) { + std::string site = + SiteInstanceImpl::GetSiteForURL(browser_context_, isolation_context_, url) + .possibly_invalid_spec(); + + auto i = site_instance_map_.find(site); + if (i != site_instance_map_.end()) + return i->second; + + // Check to see if we can use the default SiteInstance for sites that don't + // need to be isolated in their own process. The default instance allows us to + // have multiple unisolated sites share a process. We don't use the default + // instance when kProcessSharingWithStrictSiteInstances is enabled because in + // that case we want each site to have their own SiteInstance object and logic + // elsewhere ensures that those SiteInstances share a process. + if (allow_default_instance && + !base::FeatureList::IsEnabled( + features::kProcessSharingWithStrictSiteInstances) && + !SiteInstanceImpl::DoesSiteRequireDedicatedProcess( + browser_context_, isolation_context_, url)) { + DCHECK(!default_process_); + if (!default_site_instance_) { + default_site_instance_ = new SiteInstanceImpl(this); + default_site_instance_->SetSite(GURL(kDefaultInstanceSiteURL)); + } + return default_site_instance_; + } + + return nullptr; +} + void BrowsingInstance::RegisterSiteInstance(SiteInstanceImpl* site_instance) { DCHECK(site_instance->browsing_instance_.get() == this); DCHECK(site_instance->HasSite()); + // Explicitly prevent the |default_site_instance_| from being added since + // the map is only supposed to contain instances that map to a single site. + if (site_instance == default_site_instance_.get()) + return; + std::string site = site_instance->GetSiteURL().possibly_invalid_spec(); // Only register if we don't have a SiteInstance for this site already.
diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h index 474039c..e780c0f 100644 --- a/content/browser/browsing_instance.h +++ b/content/browser/browsing_instance.h
@@ -104,7 +104,37 @@ // Get the SiteInstance responsible for rendering the given URL. Should // create a new one if necessary, but should not create more than one // SiteInstance per site. - scoped_refptr<SiteInstanceImpl> GetSiteInstanceForURL(const GURL& url); + // + // |allow_default_instance| should be set to true in cases where the caller + // is ok with |url| sharing a process with other sites that do not require + // a dedicated process. Note that setting this to true means that the + // SiteInstanceImpl you get back may return "http://unisolated.invalid" for + // GetSiteURL() and lock_url() calls because the default instance is not + // bound to a single site. + scoped_refptr<SiteInstanceImpl> GetSiteInstanceForURL( + const GURL& url, + bool allow_default_instance); + + // Gets site and lock URLs for |url| that are identical with what these + // values would be if we called GetSiteInstanceForURL() with the same + // |url| and |allow_default_instance|. This method is used when we need this + // information, but do not want to create a SiteInstance yet. + void GetSiteAndLockForURL(const GURL& url, + bool allow_default_instance, + GURL* site_url, + GURL* lock_url); + + // Helper function used by GetSiteInstanceForURL() and GetSiteAndLockForURL() + // that returns an existing SiteInstance from |site_instance_map_| or + // returns |default_site_instance_| if |allow_default_instance| is true and + // other conditions are met. If there is no existing SiteInstance that is + // appropriate for |url|, |allow_default_instance| combination, then a nullptr + // is returned. + // + // Note: This method is not intended to be called by code outside this object. + scoped_refptr<SiteInstanceImpl> GetSiteInstanceForURLHelper( + const GURL& url, + bool allow_default_instance); // Adds the given SiteInstance to our map, to ensure that we do not create // another SiteInstance for the same site. @@ -129,6 +159,8 @@ void SetDefaultProcess(RenderProcessHost* default_process); RenderProcessHost* default_process() const { return default_process_; } + bool IsDefaultSiteInstance(const SiteInstanceImpl* site_instance) const; + // Map of site to SiteInstance, to ensure we only have one SiteInstance per // site. typedef std::unordered_map<std::string, SiteInstanceImpl*> SiteInstanceMap; @@ -151,6 +183,9 @@ // SiteInstances can be assigned to the same site. This is ok in rare cases. // It also does not contain SiteInstances which have not yet been assigned a // site, such as about:blank. See NavigatorImpl::ShouldAssignSiteForURL. + // This map only contains instances that map to a single site. The + // |default_site_instance_|, which associates multiple sites with a single + // instance, is not contained in this map. SiteInstanceMap site_instance_map_; // Number of WebContentses currently using this BrowsingInstance. @@ -160,6 +195,13 @@ // doesn't require a dedicated process. RenderProcessHost* default_process_; + // SiteInstance to use if a URL does not correspond to an instance in + // |site_instance_map_| and it does not require a dedicated process. + // This field and |default_process_| are mutually exclusive and this field + // should only be set if kProcessSharingWithStrictSiteInstances is not + // enabled. + scoped_refptr<SiteInstanceImpl> default_site_instance_; + DISALLOW_COPY_AND_ASSIGN(BrowsingInstance); };
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index e4fe19f7..f48d0b3 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -161,6 +161,15 @@ ChildProcessLauncherHelper::ResetRegisteredFilesForTesting(); } +#if defined(OS_ANDROID) +void ChildProcessLauncher::DumpProcessStack() { + base::Process to_pass = process_.process.Duplicate(); + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&ChildProcessLauncherHelper::DumpProcessStack, + helper_, std::move(to_pass))); +} +#endif + ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( Client* client) { Client* ret = client_;
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index 5ecd927..407bfc4 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h
@@ -210,6 +210,10 @@ // support multiple shell context creation in unit_tests. static void ResetRegisteredFilesForTesting(); +#if defined(OS_ANDROID) + // Dumps the stack of the child process without crashing it. + void DumpProcessStack(); +#endif private: friend class internal::ChildProcessLauncherHelper;
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h index 9b93e1f..301b8443 100644 --- a/content/browser/child_process_launcher_helper.h +++ b/content/browser/child_process_launcher_helper.h
@@ -190,6 +190,9 @@ void OnChildProcessStarted(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, jint handle); + + // Dumps the stack of the child process without crashing it. + void DumpProcessStack(const base::Process& process); #endif // OS_ANDROID private:
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc index de95aba..adc3cc9 100644 --- a/content/browser/child_process_launcher_helper_android.cc +++ b/content/browser/child_process_launcher_helper_android.cc
@@ -250,6 +250,14 @@ return base::File(base::android::OpenApkAsset(path.value(), region)); } +void ChildProcessLauncherHelper::DumpProcessStack( + const base::Process& process) { + JNIEnv* env = AttachCurrentThread(); + DCHECK(env); + return Java_ChildProcessLauncherHelperImpl_dumpProcessStack(env, java_peer_, + process.Handle()); +} + // Called from ChildProcessLauncher.java when the ChildProcess was started. // |handle| is the processID of the child process as originated in Java, 0 if // the ChildProcess could not be created.
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc index d90d3da5..50cc0dca 100644 --- a/content/browser/dom_storage/session_storage_context_mojo.cc +++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -237,12 +237,14 @@ bool should_persist) { auto namespace_it = namespaces_.find(namespace_id); // If the namespace has pending clones, do the clone now before destroying it. - if (namespace_it->second->HasNamespacesWaitingForClone()) { - namespace_it->second->CloneAllNamespacesWaitingForClone(); + if (namespace_it != namespaces_.end()) { + if (namespace_it->second->HasNamespacesWaitingForClone()) + namespace_it->second->CloneAllNamespacesWaitingForClone(); + + // The object hierarchy uses iterators bound to the metadata object, so + // make sure to delete the object hierarchy first. + namespaces_.erase(namespace_it); } - // The object hierarchy uses iterators bound to the metadata object, so make - // sure to delete the object hierarchy first. - namespaces_.erase(namespace_it); if (!has_scavenged_ && should_persist) protected_namespaces_from_scavenge_.insert(namespace_id); @@ -339,6 +341,12 @@ void SessionStorageContextMojo::ShutdownAndDelete() { DCHECK_NE(connection_state_, CONNECTION_SHUTDOWN); + // The namespaces will DCHECK if they are destructed with pending clones. It + // is valid for to drop these on shutdown. + for (auto& namespace_pair : namespaces_) { + namespace_pair.second->ClearNamespacesWaitingForClone(); + } + // Nothing to do if no connection to the database was ever finished. if (connection_state_ != CONNECTION_FINISHED) { connection_state_ = CONNECTION_SHUTDOWN;
diff --git a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc index 1a6c235..727afbb 100644 --- a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc +++ b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -72,6 +72,8 @@ } void TearDown() override { + if (context_) + ShutdownContext(); ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kTestProcessId); mojo::core::SetDefaultProcessErrorCallback(
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc index 62ba8210..813792d 100644 --- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc +++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
@@ -92,6 +92,7 @@ populated_ = false; origin_areas_.clear(); bindings_.CloseAllBindings(); + namespaces_waiting_for_clone_call_.clear(); } void SessionStorageNamespaceImplMojo::Bind(
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h index d0e2b12..38f8579 100644 --- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h +++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
@@ -108,7 +108,10 @@ const OriginAreas& areas_to_clone); // Resets to a pre-populated and pre-bound state. Used when the owner needs to - // delete & recreate the database. + // delete & recreate the database. This call should happen on every namespace + // at once, and the logic relies on that. + // TODO(dmurph): It's unclear if we need this or not - we might just want to + // destruct the object instead of having this method. void Reset(); SessionStorageMetadata::NamespaceEntry namespace_entry() { @@ -158,6 +161,13 @@ } void CloneAllNamespacesWaitingForClone(); + // This is only used on shutdown to avoid the DCHECK in the destructor. + // We are fine to drop clone calls during shutdown, even if this loses some + // data. + void ClearNamespacesWaitingForClone() { + namespaces_waiting_for_clone_call_.clear(); + } + private: FRIEND_TEST_ALL_PREFIXES(SessionStorageContextMojoTest, PurgeMemoryDoesNotCrashOrHang);
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc index e8201d40..0767a19 100644 --- a/content/browser/frame_host/frame_tree_node.cc +++ b/content/browser/frame_host/frame_tree_node.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_util.h" #include "content/browser/devtools/devtools_instrumentation.h" #include "content/browser/frame_host/frame_tree.h" +#include "content/browser/frame_host/navigation_controller_impl.h" #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" @@ -579,6 +580,9 @@ } } + static_cast<NavigationControllerImpl*>(navigator()->GetController()) + ->NotifyUserActivation(); + return true; }
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 71a0a5f..90cfe80 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -423,6 +423,23 @@ } #endif // DCHECK_IS_ON() +// Resets |should_skip_on_back_forward_ui| flag for |entry| if it has a frame +// entry for |root_frame| with the same document sequence number as +// |document_sequence_number|. +bool ResetSkippableForSameDocumentEntry(FrameTreeNode* root_frame, + int64_t& document_sequence_number, + NavigationEntryImpl* entry) { + if (entry && entry->should_skip_on_back_forward_ui()) { + auto* frame_entry = entry->GetFrameEntry(root_frame); + if (frame_entry && + frame_entry->document_sequence_number() == document_sequence_number) { + entry->set_should_skip_on_back_forward_ui(false); + return true; + } + } + return false; +} + } // namespace // NavigationControllerImpl ---------------------------------------------------- @@ -2075,6 +2092,44 @@ } #endif +void NavigationControllerImpl::NotifyUserActivation() { + // When a user activation occurs, ensure that all adjacent entries for the + // same document clear their skippable bit, so that the history manipulation + // intervention does not apply to them. + auto* last_committed_entry = GetLastCommittedEntry(); + if (!last_committed_entry) + return; + int last_committed_entry_index = GetLastCommittedEntryIndex(); + + auto* root_frame = delegate_->GetFrameTree()->root(); + auto* frame_entry = last_committed_entry->GetFrameEntry(root_frame); + if (!frame_entry) + return; + + int64_t document_sequence_number = frame_entry->document_sequence_number(); + + // |last_committed_entry| should not be skippable because it is the current + // entry and in case the skippable bit was earlier set then on re-navigation + // it would have been reset. + DCHECK(!last_committed_entry->should_skip_on_back_forward_ui()); + + for (int index = last_committed_entry_index - 1; index >= 0; index--) { + auto* entry = GetEntryAtIndex(index); + if (!ResetSkippableForSameDocumentEntry(root_frame, + document_sequence_number, entry)) { + break; + } + } + for (int index = last_committed_entry_index + 1; index < GetEntryCount(); + index++) { + auto* entry = GetEntryAtIndex(index); + if (!ResetSkippableForSameDocumentEntry(root_frame, + document_sequence_number, entry)) { + break; + } + } +} + bool NavigationControllerImpl::StartHistoryNavigationInNewSubframe( RenderFrameHostImpl* render_frame_host, const GURL& default_url) {
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h index d891162c3..32f6207e 100644 --- a/content/browser/frame_host/navigation_controller_impl.h +++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -238,6 +238,10 @@ const scoped_refptr<const base::RefCountedString>& data_url_as_string); #endif + // Invoked when a user activation occurs within the page, so that relevant + // entries can be updated as needed. + void NotifyUserActivation(); + private: friend class RestoreHelper;
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 3304971a..af81884 100644 --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -8734,6 +8734,166 @@ "Navigation.BackForward.SetShouldSkipOnBackForwardUI", false, 1); } +// Tests that if a navigation entry is marked as skippable due to pushState then +// the flag should be reset if there is a user gesture on this document. All of +// the adjacent entries belonging to the same document will have their skippable +// bits reset. +IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest, + OnUserGestureResetSameDocumentEntriesSkipFlag) { + GURL skippable_url(embedded_test_server()->GetURL("/frame_tree/top.html")); + EXPECT_TRUE(NavigateToURL(shell(), skippable_url)); + + // It is safe to obtain the root frame tree node here, as it doesn't change. + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + + EXPECT_FALSE(root->HasBeenActivated()); + EXPECT_FALSE(root->HasTransientUserActivation()); + + NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + + // Redirect to another page without a user gesture. + GURL redirected_url(embedded_test_server()->GetURL("/empty.html")); + EXPECT_TRUE( + NavigateToURLFromRendererWithoutUserGesture(shell(), redirected_url)); + // Last entry should have been marked as skippable. + EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); + + // Use the pushState API to add another entry without user gesture. + GURL push_state_url1(embedded_test_server()->GetURL("/title1.html")); + std::string script("history.pushState('', '','" + push_state_url1.spec() + + "');"); + EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(shell()->web_contents(), + script)); + + // Use the pushState API to add another entry without user gesture. + GURL push_state_url2(embedded_test_server()->GetURL("/title2.html")); + script = "history.pushState('', '','" + push_state_url2.spec() + "');"; + EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(shell()->web_contents(), + script)); + + EXPECT_EQ(3, controller.GetCurrentEntryIndex()); + EXPECT_EQ(3, controller.GetLastCommittedEntryIndex()); + + // We now have + // [skippable_url(skip), redirected_url(skip), push_state_url1(skip), + // push_state_url2*] + // Last 2 entries should have been marked as skippable. + EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui()); + EXPECT_TRUE(controller.GetEntryAtIndex(2)->should_skip_on_back_forward_ui()); + EXPECT_FALSE( + controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui()); + + EXPECT_EQ(skippable_url, controller.GetEntryAtIndex(0)->GetURL()); + EXPECT_EQ(redirected_url, controller.GetEntryAtIndex(1)->GetURL()); + EXPECT_EQ(push_state_url1, controller.GetEntryAtIndex(2)->GetURL()); + EXPECT_EQ(push_state_url2, controller.GetEntryAtIndex(3)->GetURL()); + + // Do another pushState so push_state_url2's entry also becomes skippable. + GURL push_state_url3(embedded_test_server()->GetURL("/title3.html")); + script = "history.pushState('', '','" + push_state_url3.spec() + "');"; + EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(shell()->web_contents(), + script)); + EXPECT_TRUE(controller.GetEntryAtIndex(3)->should_skip_on_back_forward_ui()); + // We now have + // [skippable_url(skip), redirected_url(skip), push_state_url1(skip), + // push_state_url2(skip), push_state_url3*] + + // Go to index 2. + TestNavigationObserver load_observer(shell()->web_contents()); + controller.GoToIndex(2); + load_observer.Wait(); + EXPECT_EQ(push_state_url1, controller.GetLastCommittedEntry()->GetURL()); + + // We now have (Before user gesture) + // [skippable_url(skip), redirected_url(skip), push_state_url1*, + // push_state_url2(skip), push_state_url3] + EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); + EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(2)->should_skip_on_back_forward_ui()); + EXPECT_TRUE(controller.GetEntryAtIndex(3)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(4)->should_skip_on_back_forward_ui()); + + // Simulate a user gesture. + root->UpdateUserActivationState( + blink::UserActivationUpdateType::kNotifyActivation); + + // We now have (After user gesture) + // [skippable_url(skip), redirected_url, push_state_url1*, push_state_url2, + // push_state_url3] + // All the navigations that refer to the same document should have their + // skippable bit reset. + EXPECT_FALSE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(2)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(3)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(4)->should_skip_on_back_forward_ui()); + // The first entry is not the same document and its bit should not be reset. + EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); + + // goBack should now navigate to entry at index 1. + TestNavigationObserver back_load_observer(shell()->web_contents()); + controller.GoBack(); + back_load_observer.Wait(); + EXPECT_EQ(redirected_url, controller.GetLastCommittedEntry()->GetURL()); + + // Do another pushState without user gesture. + GURL push_state_url4(embedded_test_server()->GetURL("/title3.html")); + script = "history.pushState('', '','" + push_state_url3.spec() + "');"; + EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(shell()->web_contents(), + script)); + // We now have + // [skippable_url(skip), redirected_url, push_state_url4*] + EXPECT_EQ(3, controller.GetEntryCount()); + EXPECT_EQ(skippable_url, controller.GetEntryAtIndex(0)->GetURL()); + EXPECT_EQ(redirected_url, controller.GetEntryAtIndex(1)->GetURL()); + EXPECT_EQ(push_state_url4, controller.GetEntryAtIndex(2)->GetURL()); + // The skippable flag will still be unset since this page has seen a user + // gesture once. + EXPECT_FALSE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui()); +} + +// Tests that if a navigation entry is marked as skippable due to redirect to a +// new document then the flag should not be reset if there is a user gesture on +// the new document. +IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest, + OnUserGestureDoNotResetDifferentDocumentEntrySkipFlag) { + GURL skippable_url(embedded_test_server()->GetURL("/frame_tree/top.html")); + EXPECT_TRUE(NavigateToURL(shell(), skippable_url)); + + // It is safe to obtain the root frame tree node here, as it doesn't change. + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + + EXPECT_FALSE(root->HasBeenActivated()); + EXPECT_FALSE(root->HasTransientUserActivation()); + + // Navigate to a new same-site document from the renderer without a user + // gesture. + GURL redirected_url(embedded_test_server()->GetURL("/title1.html")); + EXPECT_TRUE( + NavigateToURLFromRendererWithoutUserGesture(shell(), redirected_url)); + + NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + EXPECT_EQ(1, controller.GetCurrentEntryIndex()); + EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); + + EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); + EXPECT_FALSE( + controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui()); + + // Simulate a user gesture. + root->UpdateUserActivationState( + blink::UserActivationUpdateType::kNotifyActivation); + + // Since the last navigations refer to a different document, a user gesture + // here should not reset the skippable bit in the previous entries. + EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); +} + // Tests that the navigation entry is not marked as skippable on back/forward // button if it does a renderer initiated navigation after getting a user // activation.
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc index cc26ba06..8e0460d 100644 --- a/content/browser/frame_host/navigator_impl_unittest.cc +++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -1009,14 +1009,22 @@ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2, SiteInstanceRelation::RELATED); related_instance = ConvertToSiteInstance(rfhm, descriptor, nullptr); - // Should return a new instance, related to the current, set to the new site - // URL. + // If kUrlSameSiteAs2 requires a dedicated process on this platform, this + // should return a new instance, related to the current and set to the new + // site URL. + // Otherwise, this should return the default site instance EXPECT_TRUE( current_instance->IsRelatedSiteInstance(related_instance.get())); EXPECT_NE(current_instance, related_instance.get()); EXPECT_NE(unrelated_instance.get(), related_instance.get()); - EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2), - related_instance->GetSiteURL()); + + if (AreAllSitesIsolatedForTesting()) { + EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2), + related_instance->GetSiteURL()); + } else { + EXPECT_TRUE(static_cast<SiteInstanceImpl*>(related_instance.get()) + ->IsDefaultSiteInstance()); + } } // 5) Convert a descriptor of an unrelated instance with the same site as the
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc index 022a16c..9b7945e 100644 --- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -4654,9 +4654,17 @@ EXPECT_EQ(test_url, child1->current_frame_host()->GetLastCommittedURL()); EXPECT_EQ(url::Origin::Create(test_url), child1->current_frame_host()->GetLastCommittedOrigin()); - GURL c_site_url = - child1->current_frame_host()->GetSiteInstance()->GetSiteURL(); - EXPECT_EQ("c.com", c_site_url.host()); + + SiteInstanceImpl* child1_site_instance = + child1->current_frame_host()->GetSiteInstance(); + + GURL c_site_url = child1_site_instance->GetSiteURL(); + if (AreAllSitesIsolatedForTesting()) { + EXPECT_EQ("c.com", c_site_url.host()); + EXPECT_EQ(test_url.host(), c_site_url.host()); + } else { + EXPECT_TRUE(child1_site_instance->IsDefaultSiteInstance()); + } EXPECT_NE(a_site_url, c_site_url); EXPECT_NE(b_site_url, c_site_url); }
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index 0a7c48d..0b81d93 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -1208,7 +1208,7 @@ EXPECT_EQ(expected_to_isolate, IsIsolatedOrigin(GURL("https://bar.com/"))); } -// This is a regresion test for https://crbug.com/793350 - the long list of +// This is a regression test for https://crbug.com/793350 - the long list of // origins to isolate used to be unnecessarily propagated to the renderer // process, trigerring a crash due to exceeding kZygoteMaxMessageLength. class IsolatedOriginLongListTest : public IsolatedOriginTestBase { @@ -1442,6 +1442,74 @@ EXPECT_TRUE(IsIsolatedOrigin(isolated_url)); } +// Verify that main frame's origin isolation still keeps all same-origin frames +// in the same process. When allocating processes for a(b(c),d(c)), we should +// ensure that "c" frames are in the same process. +// +// This is a regression test for https://crbug.com/787576. +IN_PROC_BROWSER_TEST_F(IsolatedOriginNoFlagOverrideTest, + SameOriginSubframesProcessSharing) { + GURL main_url(embedded_test_server()->GetURL( + "isolated.foo.com", "/cross_site_iframe_factory.html?a(b(c),d(c))")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + RenderFrameHost* a = root->current_frame_host(); + RenderFrameHost* b = root->child_at(0)->current_frame_host(); + RenderFrameHost* c1 = root->child_at(0)->child_at(0)->current_frame_host(); + RenderFrameHost* d = root->child_at(1)->current_frame_host(); + RenderFrameHost* c2 = root->child_at(1)->child_at(0)->current_frame_host(); + + // Sanity check that the test works with the right frame tree. + EXPECT_TRUE(IsIsolatedOrigin(a->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(b->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(d->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(c1->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(c2->GetLastCommittedOrigin())); + EXPECT_EQ("b.com", b->GetLastCommittedURL().host()); + EXPECT_EQ("d.com", d->GetLastCommittedURL().host()); + EXPECT_EQ("c.com", c1->GetLastCommittedURL().host()); + EXPECT_EQ("c.com", c2->GetLastCommittedURL().host()); + + // Verify that the isolated site is indeed isolated. + EXPECT_NE(a->GetProcess()->GetID(), c1->GetProcess()->GetID()); + EXPECT_NE(a->GetProcess()->GetID(), c2->GetProcess()->GetID()); + EXPECT_NE(a->GetProcess()->GetID(), b->GetProcess()->GetID()); + EXPECT_NE(a->GetProcess()->GetID(), d->GetProcess()->GetID()); + + // Verify that same-origin c1 and c2 frames share a process. This is + // necessary for correctness - otherwise c1 and c2 wouldn't be able to + // synchronously script each other. + EXPECT_EQ(c1->GetProcess()->GetID(), c2->GetProcess()->GetID()); + + // Verify that same-origin c1 and c2 frames can script each other. + EXPECT_TRUE(ExecuteScript(c1, "window.name = 'c1';")); + EXPECT_TRUE(ExecuteScript(c2, R"( + c1 = window.open('', 'c1'); + c1.cross_frame_property_test = 'hello from c2'; )")); + std::string actual_property_value; + EXPECT_TRUE(ExecuteScriptAndExtractString( + c1, "domAutomationController.send(window.cross_frame_property_test);", + &actual_property_value)); + EXPECT_EQ("hello from c2", actual_property_value); + + // The test assertions below are not strictly necessary - they just document + // the current behavior and might be tweaked if needed. In particular, + // consolidating b,c,d sites into the same process is not necessary for + // correctness. Consolidation might be desirable if we want to limit the + // number of renderer processes. OTOH, consolidation might be undesirable + // if we desire smaller renderer processes (even if it means more processes). + if (!AreAllSitesIsolatedForTesting()) { + EXPECT_EQ(b->GetProcess()->GetID(), c1->GetProcess()->GetID()); + EXPECT_EQ(b->GetProcess()->GetID(), c2->GetProcess()->GetID()); + EXPECT_EQ(b->GetProcess()->GetID(), d->GetProcess()->GetID()); + } else { + EXPECT_NE(b->GetProcess()->GetID(), c1->GetProcess()->GetID()); + EXPECT_NE(b->GetProcess()->GetID(), c2->GetProcess()->GetID()); + EXPECT_NE(b->GetProcess()->GetID(), d->GetProcess()->GetID()); + EXPECT_EQ(c1->GetProcess()->GetID(), c2->GetProcess()->GetID()); + } +} + // Helper class for testing dynamically-added isolated origins. Tests that use // this run without full --site-per-process, but with two isolated origins that // are configured at startup (isolated.foo.com and isolated.bar.com).
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 161ab06..2ee25ad 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -494,10 +494,8 @@ resource_context_, url_request_context_getter->GetURLRequestContext(), upload_file_system_context, *request_info_, std::move(navigation_ui_data_), std::move(url_loader_client), - std::move(url_loader), - nullptr /* service_worker_navigation_handle_core */, - appcache_handle_core, options, resource_request_->priority, - global_request_id_); + std::move(url_loader), appcache_handle_core, options, + resource_request_->priority, global_request_id_); } // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 6a0b176..2247abad 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -56,8 +56,6 @@ #include "content/browser/loader/throttling_resource_handler.h" #include "content/browser/loader/upload_data_stream_builder.h" #include "content/browser/resource_context_impl.h" -#include "content/browser/service_worker/service_worker_context_wrapper.h" -#include "content/browser/service_worker/service_worker_navigation_handle_core.h" #include "content/browser/service_worker/service_worker_request_handler.h" #include "content/browser/streams/stream.h" #include "content/browser/streams/stream_context.h" @@ -1502,7 +1500,6 @@ std::unique_ptr<NavigationUIData> navigation_ui_data, network::mojom::URLLoaderClientPtr url_loader_client, network::mojom::URLLoaderRequest url_loader_request, - ServiceWorkerNavigationHandleCore* service_worker_handle_core, AppCacheNavigationHandleCore* appcache_handle_core, uint32_t url_loader_options, net::RequestPriority net_priority, @@ -1586,10 +1583,7 @@ // TODO(davidben): Associate the request with the FrameTreeNode and/or tab so // that IO thread -> UI thread hops will work. ResourceRequestInfoImpl* extra_info = new ResourceRequestInfoImpl( - ResourceRequesterInfo::CreateForBrowserSideNavigation( - service_worker_handle_core - ? service_worker_handle_core->context_wrapper() - : scoped_refptr<ServiceWorkerContextWrapper>()), + ResourceRequesterInfo::CreateForBrowserSideNavigation(), -1, // route_id info.frame_tree_node_id, ChildProcessHost::kInvalidUniqueID, // plugin_child_id @@ -1632,16 +1626,6 @@ blob_context->GetBlobDataFromPublicURL(new_request->url())); } - network::mojom::RequestContextFrameType frame_type = - info.is_main_frame ? network::mojom::RequestContextFrameType::kTopLevel - : network::mojom::RequestContextFrameType::kNested; - ServiceWorkerRequestHandler::InitializeForNavigation( - new_request.get(), service_worker_handle_core, blob_context, - info.begin_params->skip_service_worker, resource_type, - info.begin_params->request_context_type, frame_type, - info.are_ancestors_secure, info.common_params.post_data, - extra_info->GetWebContentsGetterForRequest()); - // Have the appcache associate its extra info with the request. if (appcache_handle_core) { AppCacheInterceptor::SetExtraRequestInfoForHost(
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 3bb8c72f..dfeee02 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -77,7 +77,6 @@ class ResourceMessageDelegate; class ResourceRequesterInfo; class ResourceRequestInfoImpl; -class ServiceWorkerNavigationHandleCore; struct NavigationRequestInfo; struct Referrer; struct ResourceRequest; @@ -235,7 +234,6 @@ std::unique_ptr<NavigationUIData> navigation_ui_data, network::mojom::URLLoaderClientPtr url_loader_client, network::mojom::URLLoaderRequest url_loader_request, - ServiceWorkerNavigationHandleCore* service_worker_handle_core, AppCacheNavigationHandleCore* appcache_handle_core, uint32_t url_loader_options, net::RequestPriority net_priority,
diff --git a/content/browser/loader/resource_requester_info.cc b/content/browser/loader/resource_requester_info.cc index 17c8b70..b16ba18 100644 --- a/content/browser/loader/resource_requester_info.cc +++ b/content/browser/loader/resource_requester_info.cc
@@ -89,13 +89,12 @@ } scoped_refptr<ResourceRequesterInfo> -ResourceRequesterInfo::CreateForBrowserSideNavigation( - scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) { +ResourceRequesterInfo::CreateForBrowserSideNavigation() { return scoped_refptr<ResourceRequesterInfo>(new ResourceRequesterInfo( RequesterType::BROWSER_SIDE_NAVIGATION, ChildProcessHost::kInvalidUniqueID, nullptr /* appcache_service */, nullptr /* blob_storage_context */, nullptr /* file_system_context */, - service_worker_context.get(), GetContextsCallback())); + nullptr /* service_worker_context */, GetContextsCallback())); } scoped_refptr<ResourceRequesterInfo>
diff --git a/content/browser/loader/resource_requester_info.h b/content/browser/loader/resource_requester_info.h index 762feb7..24027c6 100644 --- a/content/browser/loader/resource_requester_info.h +++ b/content/browser/loader/resource_requester_info.h
@@ -60,8 +60,7 @@ // Creates a ResourceRequesterInfo for a requester that requests resources // within the browser process for browser side navigation (aka PlzNavigate). - static scoped_refptr<ResourceRequesterInfo> CreateForBrowserSideNavigation( - scoped_refptr<ServiceWorkerContextWrapper> service_worker_context); + static scoped_refptr<ResourceRequesterInfo> CreateForBrowserSideNavigation(); // Creates a ResourceRequesterInfo for a requester that requests resources for // download or page save.
diff --git a/content/browser/media/android/browser_gpu_video_accelerator_factories.cc b/content/browser/media/android/browser_gpu_video_accelerator_factories.cc index a38b48a..fddfec8 100644 --- a/content/browser/media/android/browser_gpu_video_accelerator_factories.cc +++ b/content/browser/media/android/browser_gpu_video_accelerator_factories.cc
@@ -106,8 +106,7 @@ std::unique_ptr<media::VideoDecoder> BrowserGpuVideoAcceleratorFactories::CreateVideoDecoder( media::MediaLog* media_log, - const media::RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) { + const media::RequestOverlayInfoCB& request_overlay_info_cb) { return nullptr; }
diff --git a/content/browser/media/android/browser_gpu_video_accelerator_factories.h b/content/browser/media/android/browser_gpu_video_accelerator_factories.h index 7e54de7..119c857 100644 --- a/content/browser/media/android/browser_gpu_video_accelerator_factories.h +++ b/content/browser/media/android/browser_gpu_video_accelerator_factories.h
@@ -28,8 +28,7 @@ const media::VideoDecoderConfig& config) override; std::unique_ptr<media::VideoDecoder> CreateVideoDecoder( media::MediaLog* media_log, - const media::RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) override; + const media::RequestOverlayInfoCB& request_overlay_info_cb) override; std::unique_ptr<media::VideoDecodeAccelerator> CreateVideoDecodeAccelerator() override; std::unique_ptr<media::VideoEncodeAccelerator> CreateVideoEncodeAccelerator()
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc index a77cfb30..e1ff9b00 100644 --- a/content/browser/media/media_interface_proxy.cc +++ b/content/browser/media/media_interface_proxy.cc
@@ -152,15 +152,6 @@ factory->CreateVideoDecoder(std::move(request)); } -// TODO(https://crbug.com/936528) : remove this method. -void MediaInterfaceProxy::CreateRenderer( - media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) { - DCHECK_EQ(type, media::mojom::HostedRendererType::kDefault); - CreateDefaultRenderer(audio_device_id, std::move(renderer)); -} - void MediaInterfaceProxy::CreateDefaultRenderer( const std::string& audio_device_id, media::mojom::RendererRequest request) {
diff --git a/content/browser/media/media_interface_proxy.h b/content/browser/media/media_interface_proxy.h index 60ecd18..f0c6bd5 100644 --- a/content/browser/media/media_interface_proxy.h +++ b/content/browser/media/media_interface_proxy.h
@@ -49,10 +49,6 @@ void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final; void CreateDefaultRenderer(const std::string& audio_device_id, media::mojom::RendererRequest request) final; - // TODO(https://crbug.com/936528) : remove this method. - void CreateRenderer(media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) final; #if defined(OS_ANDROID) void CreateFlingingRenderer(const std::string& presentation_id, media::mojom::RendererRequest request) final;
diff --git a/content/browser/media/video_decoder_proxy.cc b/content/browser/media/video_decoder_proxy.cc index d588e3f..0df8b46 100644 --- a/content/browser/media/video_decoder_proxy.cc +++ b/content/browser/media/video_decoder_proxy.cc
@@ -45,11 +45,6 @@ const std::string& audio_device_id, media::mojom::RendererRequest request) {} -// TODO(https://crbug.com/936528): remove this method. -void VideoDecoderProxy::CreateRenderer(media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest request) {} - #if defined(OS_ANDROID) void VideoDecoderProxy::CreateFlingingRenderer( const std::string& audio_device_id,
diff --git a/content/browser/media/video_decoder_proxy.h b/content/browser/media/video_decoder_proxy.h index 76708a96..23bad96 100644 --- a/content/browser/media/video_decoder_proxy.h +++ b/content/browser/media/video_decoder_proxy.h
@@ -31,10 +31,6 @@ void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final; void CreateDefaultRenderer(const std::string& audio_device_id, media::mojom::RendererRequest request) final; - // TODO(https://crbug.com/936528) : remove this method. - void CreateRenderer(media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest request) final; #if defined(OS_ANDROID) void CreateMediaPlayerRenderer(media::mojom::RendererRequest request) final; void CreateFlingingRenderer(const std::string& presentation_id,
diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc index 22b3836..f251139f 100644 --- a/content/browser/notifications/blink_notification_service_impl.cc +++ b/content/browser/notifications/blink_notification_service_impl.cc
@@ -57,7 +57,7 @@ if (include_triggered) return true; // Notifications without a trigger always match. - if (!database_data.notification_data.show_trigger_timestamp.has_value()) + if (!database_data.notification_data.show_trigger_timestamp) return true; // Otherwise it has to be triggered already. return database_data.has_triggered; @@ -211,8 +211,12 @@ // TODO(https://crbug.com/870258): Validate resources are not too big (either // here or in the mojo struct traits). - if (platform_notification_data.show_trigger_timestamp.has_value()) + if (platform_notification_data.show_trigger_timestamp && + base::FeatureList::IsEnabled(features::kNotificationTriggers)) { + // TODO(knollr): Let PlatformNotificationContext display all notifications, + // even non scheduled ones and always set resources here. database_data.notification_resources = notification_resources; + } notification_context_->WriteNotificationData( next_persistent_id, service_worker_registration_id, origin_.GetURL(), @@ -237,6 +241,16 @@ return; } + if (platform_notification_data.show_trigger_timestamp && + base::FeatureList::IsEnabled(features::kNotificationTriggers)) { + // This notification will be handled by the |notification_context_| because + // it has to be scheduled rather than displayed immediately. + // TODO(knollr): Let PlatformNotificationContext display all notifications, + // even non scheduled ones to make this code path go away. + std::move(callback).Run(PersistentNotificationError::NONE); + return; + } + base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(
diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc index e0958af4..a2fb2bb 100644 --- a/content/browser/notifications/blink_notification_service_impl_unittest.cc +++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc
@@ -778,6 +778,9 @@ } TEST_F(BlinkNotificationServiceImplTest, GetTriggeredNotificationsWithFilter) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kNotificationTriggers); + SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED); scoped_refptr<ServiceWorkerRegistration> registration; @@ -815,6 +818,9 @@ } TEST_F(BlinkNotificationServiceImplTest, ResourcesStoredForTriggered) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kNotificationTriggers); + SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED); scoped_refptr<ServiceWorkerRegistration> registration; @@ -862,4 +868,27 @@ EXPECT_FALSE(stored_resources_b.has_value()); } +TEST_F(BlinkNotificationServiceImplTest, NotCallingDisplayForTriggered) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kNotificationTriggers); + + SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED); + + scoped_refptr<ServiceWorkerRegistration> registration; + RegisterServiceWorker(®istration); + + base::Time timestamp = base::Time::Now() + base::TimeDelta::FromSeconds(10); + blink::PlatformNotificationData scheduled_notification_data; + scheduled_notification_data.show_trigger_timestamp = timestamp; + blink::NotificationResources resources; + + DisplayPersistentNotificationSync(registration->id(), + scheduled_notification_data, resources); + + // Wait for service to receive all the Display calls. + RunAllTasksUntilIdle(); + + EXPECT_EQ(0u, GetDisplayedNotifications().size()); +} + } // namespace content
diff --git a/content/browser/notifications/notification_trigger_constants.h b/content/browser/notifications/notification_trigger_constants.h new file mode 100644 index 0000000..3d5a1e0 --- /dev/null +++ b/content/browser/notifications/notification_trigger_constants.h
@@ -0,0 +1,15 @@ +// Copyright 2019 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_BROWSER_NOTIFICATIONS_NOTIFICATION_TRIGGER_CONSTANTS_H_ +#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_TRIGGER_CONSTANTS_H_ + +namespace content { + +// Maximum number of currently scheduled notifications per origin. +constexpr int kMaximumScheduledNotificationsPerOrigin = 30; + +} // namespace content + +#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_TRIGGER_CONSTANTS_H_
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc index 693aa19..9d43b4e 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -8,12 +8,15 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/feature_list.h" #include "base/files/file_util.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/task/post_task.h" #include "content/browser/notifications/blink_notification_service_impl.h" #include "content/browser/notifications/notification_database.h" +#include "content/browser/notifications/notification_trigger_constants.h" +#include "content/browser/notifications/platform_notification_service_proxy.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -21,6 +24,7 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/notification_database_data.h" #include "content/public/browser/platform_notification_service.h" +#include "content/public/common/content_features.h" #include "third_party/blink/public/common/notifications/notification_resources.h" namespace content { @@ -31,6 +35,13 @@ const base::FilePath::CharType kPlatformNotificationsDirectory[] = FILE_PATH_LITERAL("Platform Notifications"); +// Checks if this notification can trigger in the future. +bool CanTrigger(const NotificationDatabaseData& data) { + if (!base::FeatureList::IsEnabled(features::kNotificationTriggers)) + return false; + return data.notification_data.show_trigger_timestamp && !data.has_triggered; +} + } // namespace PlatformNotificationContextImpl::PlatformNotificationContextImpl( @@ -56,6 +67,9 @@ void PlatformNotificationContextImpl::Initialize() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + service_proxy_ = std::make_unique<PlatformNotificationServiceProxy>( + service_worker_context_, browser_context_); + PlatformNotificationService* service = GetContentClient()->browser()->GetPlatformNotificationService(); if (!service) { @@ -84,10 +98,11 @@ // because flakiness may cause a platform to inform Chrome of a notification // that has since been closed, or because the platform does not support // notifications that exceed the lifetime of the browser process. - if (supports_synchronization) { - LazyInitialize( - base::BindOnce(&PlatformNotificationContextImpl::DoSyncNotificationData, - this, std::move(displayed_notifications))); + if (supports_synchronization || + base::FeatureList::IsEnabled(features::kNotificationTriggers)) { + LazyInitialize(base::BindOnce( + &PlatformNotificationContextImpl::DoSyncNotificationData, this, + supports_synchronization, std::move(displayed_notifications))); } // |service_worker_context_| may be NULL in tests. @@ -96,28 +111,57 @@ } void PlatformNotificationContextImpl::DoSyncNotificationData( + bool supports_synchronization, std::set<std::string> displayed_notifications, bool initialized) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); if (!initialized) return; - // Iterate over all notifications and delete all expired ones. Passing |this| - // as Unretained is safe as this is synchronous. + // Reset |next_trigger_| to keep track of the next trigger timestamp. + next_trigger_ = base::nullopt; + + // Iterate over all notifications and delete all expired ones. NotificationDatabase::Status status = database_->ForEachNotificationData(base::BindRepeating( - &PlatformNotificationContextImpl::DoHandleSyncNotification, - base::Unretained(this), displayed_notifications)); + &PlatformNotificationContextImpl::DoHandleSyncNotification, this, + supports_synchronization, displayed_notifications)); // Blow away the database if reading data failed due to corruption. if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) DestroyDatabase(); + + // Schedule the next trigger timestamp. + if (next_trigger_) { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&PlatformNotificationContextImpl::ScheduleTrigger, this, + next_trigger_.value())); + } } void PlatformNotificationContextImpl::DoHandleSyncNotification( + bool supports_synchronization, const std::set<std::string>& displayed_notifications, const NotificationDatabaseData& data) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); + // Handle pending notifications. + if (CanTrigger(data)) { + base::Time timestamp = + data.notification_data.show_trigger_timestamp.value(); + // Check if we should display this notification. + if (timestamp <= base::Time::Now()) + DoTriggerNotification(data); + else if (!next_trigger_ || next_trigger_.value() > timestamp) + next_trigger_ = timestamp; + return; + } + + // Do not delete notifications if the platform does not support syncing them. + if (!supports_synchronization) + return; + + // Delete notifications that are not on screen anymore. if (!displayed_notifications.count(data.notification_id)) database_->DeleteNotificationData(data.notification_id, data.origin); } @@ -125,6 +169,7 @@ void PlatformNotificationContextImpl::Shutdown() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + service_proxy_.reset(); services_.clear(); // |service_worker_context_| may be NULL in tests. @@ -203,6 +248,61 @@ NotificationDatabaseData())); } +void PlatformNotificationContextImpl::ScheduleTrigger(base::Time timestamp) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + base::TimeDelta delay = timestamp - base::Time::Now(); + if (delay.InMicroseconds() < 0) + delay = base::TimeDelta(); + + if (trigger_timer_.IsRunning() && trigger_timer_.GetCurrentDelay() <= delay) + return; + + trigger_timer_.Start(FROM_HERE, delay, this, + &PlatformNotificationContextImpl::TriggerNotifications); +} + +void PlatformNotificationContextImpl::TriggerNotifications() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + std::set<std::string> displayed_notifications; + LazyInitialize(base::BindOnce( + &PlatformNotificationContextImpl::DoSyncNotificationData, this, + /* supports_synchronization= */ false, + std::move(displayed_notifications))); +} + +void PlatformNotificationContextImpl::DoTriggerNotification( + const NotificationDatabaseData& database_data) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + // Bail out in case we can not display the notification after Shutdown. + if (!service_proxy_) + return; + + blink::NotificationResources resources; + NotificationDatabase::Status status = database_->ReadNotificationResources( + database_data.notification_id, database_data.origin, &resources); + + if (status != NotificationDatabase::STATUS_OK) { + // TODO(knollr): add UMA for this + resources = blink::NotificationResources(); + } + + // Create a copy of the |database_data| to store the |has_triggered| flag. + NotificationDatabaseData write_database_data = database_data; + write_database_data.has_triggered = true; + status = database_->WriteNotificationData(write_database_data.origin, + write_database_data); + + if (status != NotificationDatabase::STATUS_OK) { + database_->DeleteNotificationData(write_database_data.notification_id, + write_database_data.origin); + return; + } + + write_database_data.notification_resources = std::move(resources); + service_proxy_->DisplayNotification(std::move(write_database_data), + base::DoNothing()); +} + void PlatformNotificationContextImpl::ReadNotificationResources( const std::string& notification_id, const GURL& origin, @@ -329,7 +429,8 @@ // The database is only used for persistent notifications. DCHECK(NotificationIdGenerator::IsPersistentNotification( it->notification_id)); - if (displayed_notifications.count(it->notification_id)) { + if (displayed_notifications.count(it->notification_id) || + CanTrigger(*it)) { ++it; } else { obsolete_notifications.push_back(it->notification_id); @@ -372,6 +473,28 @@ database_data, std::move(callback))); } +bool PlatformNotificationContextImpl::DoCheckNotificationTriggerQuota( + const GURL& origin) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + int notification_count = 0; + // Iterate over all notifications and count all scheduled notifications for + // |origin|. + NotificationDatabase::Status status = + database_->ForEachNotificationData(base::BindRepeating( + [](const GURL& expected_origin, int* count, + const NotificationDatabaseData& data) { + if (CanTrigger(data) && data.origin == expected_origin) + *count = *count + 1; + }, + origin, ¬ification_count)); + + // Blow away the database if reading data failed due to corruption. + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) + DestroyDatabase(); + + return notification_count < kMaximumScheduledNotificationsPerOrigin; +} + void PlatformNotificationContextImpl::DoWriteNotificationData( int64_t service_worker_registration_id, int64_t persistent_notification_id, @@ -389,6 +512,12 @@ return; } + bool replaces_existing = false; + std::string notification_id = + notification_id_generator_.GenerateForPersistentNotification( + origin, database_data.notification_data.tag, + persistent_notification_id); + // Eagerly delete data for replaced notifications from the database. if (!database_data.notification_data.tag.empty()) { std::set<std::string> deleted_notification_ids; @@ -397,6 +526,8 @@ origin, database_data.notification_data.tag, &deleted_notification_ids); + replaces_existing = deleted_notification_ids.count(notification_id) != 0; + UMA_HISTOGRAM_ENUMERATION("Notifications.Database.DeleteBeforeWriteResult", delete_status, NotificationDatabase::STATUS_COUNT); @@ -417,10 +548,18 @@ // Create a copy of the |database_data| to store a generated notification ID. NotificationDatabaseData write_database_data = database_data; - write_database_data.notification_id = - notification_id_generator_.GenerateForPersistentNotification( - origin, database_data.notification_data.tag, - persistent_notification_id); + write_database_data.notification_id = notification_id; + write_database_data.origin = origin; + + if (CanTrigger(write_database_data) && + !DoCheckNotificationTriggerQuota(origin)) { + // TODO(knollr): Reply with a custom error so developers can handle this. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(std::move(callback), /* success= */ false, + /* notification_id= */ "")); + return; + } NotificationDatabase::Status status = database_->WriteNotificationData(origin, write_database_data); @@ -429,6 +568,18 @@ NotificationDatabase::STATUS_COUNT); if (status == NotificationDatabase::STATUS_OK) { + if (CanTrigger(write_database_data)) { + if (replaces_existing) + service_proxy_->CloseNotification(notification_id); + // Schedule notification to be shown. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&PlatformNotificationContextImpl::ScheduleTrigger, + this, + write_database_data.notification_data + .show_trigger_timestamp.value())); + } + base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, base::BindOnce(std::move(callback), /* success= */ true,
diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h index 268e9ff..c7c9bc8f 100644 --- a/content/browser/notifications/platform_notification_context_impl.h +++ b/content/browser/notifications/platform_notification_context_impl.h
@@ -16,6 +16,9 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" +#include "base/time/time.h" +#include "base/timer/timer.h" #include "content/browser/notifications/notification_database.h" #include "content/browser/notifications/notification_id_generator.h" #include "content/browser/service_worker/service_worker_context_core_observer.h" @@ -39,6 +42,7 @@ class BlinkNotificationServiceImpl; class BrowserContext; struct NotificationDatabaseData; +class PlatformNotificationServiceProxy; class ServiceWorkerContextWrapper; // Implementation of the Web Notification storage context. The public methods @@ -103,6 +107,7 @@ private: friend class PlatformNotificationContextTest; + friend class PlatformNotificationContextTriggerTest; ~PlatformNotificationContextImpl() override; @@ -116,6 +121,15 @@ // called with true, otherwise it will be called with false. void LazyInitialize(InitializeResultCallback callback); + // Schedules a job to run at |timestamp| and call TriggerNotifications. + void ScheduleTrigger(base::Time timestamp); + + // Trigger all pending notifications. + void TriggerNotifications(); + + // Marks this notification as shown and displays it. + void DoTriggerNotification(const NotificationDatabaseData& database_data); + // Opens the database. Must be called on the |task_runner_| thread. |callback| // will be invoked on the |task_runner_| thread. When the database has been // successfully opened, |callback| will be called with true, otherwise it will @@ -141,12 +155,14 @@ // Synchronize displayed notifications. This removes all non-displayed // notifications from the database. - void DoSyncNotificationData(std::set<std::string> displayed_notifications, + void DoSyncNotificationData(bool supports_synchronization, + std::set<std::string> displayed_notifications, bool initialized); // Checks if the given notification is still valid, otherwise deletes it from // the database. void DoHandleSyncNotification( + bool supports_synchronization, const std::set<std::string>& displayed_notifications, const NotificationDatabaseData& data); @@ -170,6 +186,10 @@ bool supports_synchronization, bool initialized); + // Checks if the number of notifications scheduled for |origin| does not + // exceed the quota. + bool DoCheckNotificationTriggerQuota(const GURL& origin); + // Actually writes the notification database to the database. Must only be // called on the |task_runner_| thread. |callback| will be invoked on the // UI thread when the operation has completed. @@ -219,6 +239,15 @@ NotificationIdGenerator notification_id_generator_; + // Triggers pending notifications, set by ScheduleTrigger. + base::OneShotTimer trigger_timer_; + + // Keeps track of the next trigger timestamp. + base::Optional<base::Time> next_trigger_; + + // Calls through to PlatformNotificationService methods. + std::unique_ptr<PlatformNotificationServiceProxy> service_proxy_; + // The notification services are owned by the platform context, and will be // removed when either this class is destroyed or the Mojo pipe disconnects. std::vector<std::unique_ptr<BlinkNotificationServiceImpl>> services_;
diff --git a/content/browser/notifications/platform_notification_context_trigger_unittest.cc b/content/browser/notifications/platform_notification_context_trigger_unittest.cc new file mode 100644 index 0000000..9d43d36c --- /dev/null +++ b/content/browser/notifications/platform_notification_context_trigger_unittest.cc
@@ -0,0 +1,252 @@ +// Copyright 2019 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/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "base/time/time.h" +#include "content/browser/notifications/notification_trigger_constants.h" +#include "content/browser/notifications/platform_notification_context_impl.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/public/browser/notification_database_data.h" +#include "content/public/common/content_features.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "content/test/mock_platform_notification_service.h" +#include "content/test/test_content_browser_client.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/notifications/notification_resources.h" +#include "url/gurl.h" + +using base::Time; +using base::TimeDelta; + +namespace content { + +// Fake Service Worker registration id to use in tests requiring one. +const int64_t kFakeServiceWorkerRegistrationId = 42; + +class NotificationBrowserClient : public TestContentBrowserClient { + public: + NotificationBrowserClient() + : platform_notification_service_( + std::make_unique<MockPlatformNotificationService>()) {} + + PlatformNotificationService* GetPlatformNotificationService() override { + return platform_notification_service_.get(); + } + + private: + std::unique_ptr<PlatformNotificationService> platform_notification_service_; +}; + +class PlatformNotificationContextTriggerTest : public ::testing::Test { + public: + PlatformNotificationContextTriggerTest() + : thread_bundle_( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME, + base::test::ScopedTaskEnvironment::NowSource:: + MAIN_THREAD_MOCK_TIME), + success_(false) {} + + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature(features::kNotificationTriggers); + SetBrowserClientForTesting(¬ification_browser_client_); + platform_notification_service_ = + notification_browser_client_.GetPlatformNotificationService(); + platform_notification_context_ = + base::MakeRefCounted<PlatformNotificationContextImpl>( + base::FilePath(), &browser_context_, nullptr); + platform_notification_context_->SetTaskRunnerForTesting( + base::ThreadTaskRunnerHandle::Get()); + platform_notification_context_->Initialize(); + base::RunLoop().RunUntilIdle(); + } + + // Callback to provide when writing a notification to the database. + void DidWriteNotificationData(bool success, + const std::string& notification_id) { + success_ = success; + } + + // Callback to provide when deleting notification data from the database. + void DidDeleteNotificationData(bool success) { success_ = success; } + + // Callback to provide when getting displayed notifications from the + // PlatformNotificationService. + void DidGetDisplayedNotifications(std::set<std::string> notification_ids, + bool supports_synchronization) { + displayed_notification_ids_ = notification_ids; + } + + protected: + void WriteNotificationData(const std::string& tag, + base::Optional<base::Time> timestamp) { + ASSERT_TRUE( + TryWriteNotificationData("https://example.com", tag, timestamp)); + } + + bool TryWriteNotificationData(const std::string& url, + const std::string& tag, + base::Optional<base::Time> timestamp) { + GURL origin(url); + NotificationDatabaseData notification_database_data; + notification_database_data.origin = origin; + notification_database_data.service_worker_registration_id = + kFakeServiceWorkerRegistrationId; + notification_database_data.notification_data.show_trigger_timestamp = + timestamp; + notification_database_data.notification_data.tag = tag; + + platform_notification_context_->WriteNotificationData( + next_persistent_notification_id(), kFakeServiceWorkerRegistrationId, + origin, notification_database_data, + base::BindOnce( + &PlatformNotificationContextTriggerTest::DidWriteNotificationData, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + return success_; + } + + std::set<std::string> GetDisplayedNotifications() { + platform_notification_service_->GetDisplayedNotifications( + &browser_context_, + base::BindOnce(&PlatformNotificationContextTriggerTest:: + DidGetDisplayedNotifications, + base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + return displayed_notification_ids_; + } + + TestBrowserThreadBundle thread_bundle_; // Must be first member + TestBrowserContext browser_context_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; + NotificationBrowserClient notification_browser_client_; + PlatformNotificationService* platform_notification_service_; + scoped_refptr<PlatformNotificationContextImpl> platform_notification_context_; + + // Returns the next persistent notification id for tests. + int64_t next_persistent_notification_id() { + return next_persistent_notification_id_++; + } + + bool success_; + NotificationDatabaseData database_data_; + std::string notification_id_; + int64_t next_persistent_notification_id_ = 1; + std::set<std::string> displayed_notification_ids_; +}; + +TEST_F(PlatformNotificationContextTriggerTest, TriggerInFuture) { + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + // Wait until the trigger timestamp is reached. + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(10)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, TriggerInPast) { + // Trigger timestamp in the past should immediately trigger. + WriteNotificationData("1", Time::Now() - TimeDelta::FromSeconds(10)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, + OverwriteExistingTriggerInFuture) { + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(5)); + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + // Overwrites the scheduled notifications with a new trigger timestamp. + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(5)); + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(5)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, OverwriteExistingTriggerToPast) { + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(5)); + + // Overwrites the scheduled notifications with a new trigger timestamp. + WriteNotificationData("1", Time::Now() - TimeDelta::FromSeconds(10)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, + OverwriteDisplayedNotificationToPast) { + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(10)); + + // Overwrites a displayed notification with a trigger timestamp in the past. + WriteNotificationData("1", Time::Now() - TimeDelta::FromSeconds(10)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, + OverwriteDisplayedNotificationToFuture) { + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(10)); + + // Overwrites a displayed notification which hides it until the trigger + // timestamp is reached. + WriteNotificationData("1", Time::Now() + TimeDelta::FromSeconds(10)); + + ASSERT_EQ(0u, GetDisplayedNotifications().size()); + + thread_bundle_.FastForwardBy(TimeDelta::FromSeconds(10)); + ASSERT_EQ(1u, GetDisplayedNotifications().size()); +} + +TEST_F(PlatformNotificationContextTriggerTest, + LimitsNumberOfScheduledNotificationsPerOrigin) { + for (int i = 1; i <= kMaximumScheduledNotificationsPerOrigin; ++i) { + WriteNotificationData(std::to_string(i), + Time::Now() + TimeDelta::FromSeconds(i)); + } + + ASSERT_FALSE(TryWriteNotificationData( + "https://example.com", + std::to_string(kMaximumScheduledNotificationsPerOrigin + 1), + Time::Now() + + TimeDelta::FromSeconds(kMaximumScheduledNotificationsPerOrigin + 1))); + + ASSERT_TRUE(TryWriteNotificationData( + "https://example2.com", + std::to_string(kMaximumScheduledNotificationsPerOrigin + 1), + Time::Now() + + TimeDelta::FromSeconds(kMaximumScheduledNotificationsPerOrigin + 1))); +} + +TEST_F(PlatformNotificationContextTriggerTest, EnforcesLimitOnUpdate) { + for (int i = 1; i <= kMaximumScheduledNotificationsPerOrigin; ++i) { + WriteNotificationData(std::to_string(i), + Time::Now() + TimeDelta::FromSeconds(i)); + } + + ASSERT_TRUE(TryWriteNotificationData( + "https://example.com", + std::to_string(kMaximumScheduledNotificationsPerOrigin + 1), + base::nullopt)); + + ASSERT_FALSE(TryWriteNotificationData( + "https://example.com", + std::to_string(kMaximumScheduledNotificationsPerOrigin + 1), + Time::Now() + + TimeDelta::FromSeconds(kMaximumScheduledNotificationsPerOrigin + 1))); +} + +} // namespace content
diff --git a/content/browser/notifications/platform_notification_service_proxy.cc b/content/browser/notifications/platform_notification_service_proxy.cc new file mode 100644 index 0000000..8ce2ed287 --- /dev/null +++ b/content/browser/notifications/platform_notification_service_proxy.cc
@@ -0,0 +1,100 @@ +// Copyright 2019 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/notifications/platform_notification_service_proxy.h" + +#include <memory> +#include <utility> + +#include "base/logging.h" +#include "base/task/post_task.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/browser/notification_database_data.h" +#include "content/public/browser/platform_notification_service.h" + +namespace content { + +PlatformNotificationServiceProxy::PlatformNotificationServiceProxy( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + BrowserContext* browser_context) + : service_worker_context_(service_worker_context), + browser_context_(browser_context), + notification_service_( + GetContentClient()->browser()->GetPlatformNotificationService()), + weak_ptr_factory_(this) {} + +PlatformNotificationServiceProxy::~PlatformNotificationServiceProxy() = default; + +void PlatformNotificationServiceProxy::DoDisplayNotification( + const NotificationDatabaseData& data, + const GURL& service_worker_scope, + DisplayResultCallback callback) { + if (notification_service_) { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce( + &PlatformNotificationService::DisplayPersistentNotification, + base::Unretained(notification_service_), browser_context_, + data.notification_id, service_worker_scope, data.origin, + data.notification_data, + data.notification_resources.value_or( + blink::NotificationResources()))); + } + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(std::move(callback), /* success= */ true, + data.notification_id)); +} + +void PlatformNotificationServiceProxy::VerifyServiceWorkerScope( + const NotificationDatabaseData& data, + DisplayResultCallback callback, + blink::ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration) { + if (status == blink::ServiceWorkerStatusCode::kOk && + registration->scope().GetOrigin() == data.origin) { + DoDisplayNotification(data, registration->scope(), std::move(callback)); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(std::move(callback), /* success= */ false, + /* notification_id= */ "")); + } +} + +void PlatformNotificationServiceProxy::DisplayNotification( + const NotificationDatabaseData& data, + DisplayResultCallback callback) { + if (!service_worker_context_) { + DoDisplayNotification(data, GURL(), std::move(callback)); + return; + } + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO, base::TaskPriority::USER_VISIBLE}, + base::BindOnce( + &ServiceWorkerContextWrapper::FindReadyRegistrationForId, + service_worker_context_, data.service_worker_registration_id, + data.origin, + base::BindOnce( + &PlatformNotificationServiceProxy::VerifyServiceWorkerScope, + weak_ptr_factory_.GetWeakPtr(), data, std::move(callback)))); +} + +void PlatformNotificationServiceProxy::CloseNotification( + const std::string& notification_id) { + if (!notification_service_) + return; + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&PlatformNotificationService::ClosePersistentNotification, + base::Unretained(notification_service_), browser_context_, + notification_id)); +} + +} // namespace content
diff --git a/content/browser/notifications/platform_notification_service_proxy.h b/content/browser/notifications/platform_notification_service_proxy.h new file mode 100644 index 0000000..85f59099d --- /dev/null +++ b/content/browser/notifications/platform_notification_service_proxy.h
@@ -0,0 +1,77 @@ +// Copyright 2019 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_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_SERVICE_PROXY_H_ +#define CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_SERVICE_PROXY_H_ + +#include <memory> +#include <string> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" + +class GURL; + +namespace blink { +enum class ServiceWorkerStatusCode; +} // namespace blink + +namespace content { + +class BrowserContext; +struct NotificationDatabaseData; +class PlatformNotificationService; +class ServiceWorkerContextWrapper; +class ServiceWorkerRegistration; + +class CONTENT_EXPORT PlatformNotificationServiceProxy { + public: + using DisplayResultCallback = + base::OnceCallback<void(bool /* success */, + const std::string& /* notification_id */)>; + + PlatformNotificationServiceProxy( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + BrowserContext* browser_context); + + ~PlatformNotificationServiceProxy(); + + // Displays a notification with |data| and calls |callback| with the result. + // This will verify against the given |service_worker_context_| if available. + void DisplayNotification(const NotificationDatabaseData& data, + DisplayResultCallback callback); + + // Closes the notification with |notification_id|. + void CloseNotification(const std::string& notification_id); + + private: + // Actually calls |notification_service_| to display the notification after + // verifying the |service_worker_scope|. + void DoDisplayNotification(const NotificationDatabaseData& data, + const GURL& service_worker_scope, + DisplayResultCallback callback); + + // Verifies that the service worker exists and is valid for the given + // notification origin. + void VerifyServiceWorkerScope( + const NotificationDatabaseData& data, + DisplayResultCallback callback, + blink::ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration); + + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; + BrowserContext* browser_context_; + PlatformNotificationService* notification_service_; + + base::WeakPtrFactory<PlatformNotificationServiceProxy> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(PlatformNotificationServiceProxy); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_SERVICE_PROXY_H_
diff --git a/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc b/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc new file mode 100644 index 0000000..6800517 --- /dev/null +++ b/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc
@@ -0,0 +1,129 @@ +// Copyright 2019 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/accessibility/browser_accessibility.h" +#include "content/browser/renderer_host/legacy_render_widget_host_win.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_view_aura.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "ui/accessibility/accessibility_switches.h" +#include "ui/accessibility/platform/ax_fragment_root_win.h" +#include "ui/accessibility/platform/ax_platform_node.h" +#include "ui/aura/client/aura_constants.h" + +namespace content { + +struct AccessibilityLinkageTestParams { + bool is_uia_enabled; + bool is_legacy_window_disabled; +} const kTestParameters[] = {{false, false}, + {false, true}, + {true, false}, + {true, true}}; + +class AccessibilityTreeLinkageWinBrowserTest + : public ContentBrowserTest, + public ::testing::WithParamInterface<AccessibilityLinkageTestParams> { + public: + AccessibilityTreeLinkageWinBrowserTest() { + dummy_ax_platform_node_ = ui::AXPlatformNode::Create(&dummy_ax_node_); + } + + ~AccessibilityTreeLinkageWinBrowserTest() override { + dummy_ax_platform_node_->Destroy(); + dummy_ax_platform_node_ = nullptr; + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + if (GetParam().is_uia_enabled) + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ::switches::kEnableExperimentalUIAutomation); + if (GetParam().is_legacy_window_disabled) + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ::switches::kDisableLegacyIntermediateWindow); + } + + RenderWidgetHostViewAura* GetView() { + return static_cast<RenderWidgetHostViewAura*>( + shell()->web_contents()->GetRenderWidgetHostView()); + } + + gfx::NativeWindow GetParentWindow() { return GetView()->window()->parent(); } + + LegacyRenderWidgetHostHWND* GetLegacyRenderWidgetHostHWND() { + return GetView()->legacy_render_widget_host_HWND_; + } + + protected: + ui::AXPlatformNodeDelegateBase dummy_ax_node_; + ui::AXPlatformNode* dummy_ax_platform_node_; + + private: + DISALLOW_COPY_AND_ASSIGN(AccessibilityTreeLinkageWinBrowserTest); +}; + +IN_PROC_BROWSER_TEST_P(AccessibilityTreeLinkageWinBrowserTest, Linkage) { + NavigateToURL(shell(), GURL(url::kAboutBlankURL)); + + GetParentWindow()->SetProperty( + aura::client::kParentNativeViewAccessibleKey, + dummy_ax_platform_node_->GetNativeViewAccessible()); + + if (GetParam().is_legacy_window_disabled) + ASSERT_EQ(GetLegacyRenderWidgetHostHWND(), nullptr); + else + ASSERT_NE(GetLegacyRenderWidgetHostHWND(), nullptr); + + // Used by WebView to splice in the web content root accessible as a child of + // the WebView's parent + gfx::NativeViewAccessible native_view_accessible = + GetView()->GetNativeViewAccessible(); + if (GetParam().is_uia_enabled && !GetParam().is_legacy_window_disabled) { + EXPECT_EQ(native_view_accessible, + ui::AXFragmentRootWin::GetForAcceleratedWidget( + GetView()->AccessibilityGetAcceleratedWidget()) + ->GetNativeViewAccessible()); + } else { + EXPECT_EQ(native_view_accessible, GetView() + ->host() + ->GetRootBrowserAccessibilityManager() + ->GetRoot() + ->GetNativeViewAccessible()); + } + + // Used by LegacyRenderWidgetHostHWND to find the parent of the UIA fragment + // root for web content + gfx::NativeViewAccessible parent_native_view_accessible = + GetView()->GetParentNativeViewAccessible(); + EXPECT_EQ(parent_native_view_accessible, + dummy_ax_platform_node_->GetNativeViewAccessible()); + + // Used by BrowserAccessibilityManager to find the parent of the web content + // root accessible + gfx::NativeViewAccessible accessibility_native_view_accessible = + GetView()->AccessibilityGetNativeViewAccessible(); + if (GetParam().is_legacy_window_disabled) { + EXPECT_EQ(accessibility_native_view_accessible, + dummy_ax_platform_node_->GetNativeViewAccessible()); + } else { + if (GetParam().is_uia_enabled) { + EXPECT_EQ(accessibility_native_view_accessible, + ui::AXFragmentRootWin::GetForAcceleratedWidget( + GetView()->AccessibilityGetAcceleratedWidget()) + ->GetNativeViewAccessible()); + } else { + EXPECT_EQ(accessibility_native_view_accessible, + GetLegacyRenderWidgetHostHWND()->window_accessible()); + } + } +} + +INSTANTIATE_TEST_SUITE_P(, + AccessibilityTreeLinkageWinBrowserTest, + testing::ValuesIn(kTestParameters)); + +} // namespace content
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc index 330cb33..a99ca77 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.cc +++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -248,25 +248,11 @@ BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); } - RenderWidgetHostImpl* rwhi = - RenderWidgetHostImpl::From(host_->GetRenderWidgetHost()); - if (!rwhi) + gfx::NativeViewAccessible root = GetOrCreateWindowRootAccessible(); + if (root == nullptr) return static_cast<LRESULT>(0L); - BrowserAccessibilityManagerWin* manager = - static_cast<BrowserAccessibilityManagerWin*>( - rwhi->GetRootBrowserAccessibilityManager()); - if (!manager || !manager->GetRoot()) - return static_cast<LRESULT>(0L); - - BrowserAccessibilityComWin* root = - ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM(); - if (is_uia_request) { - if (!ax_fragment_root_) - ax_fragment_root_ = - std::make_unique<ui::AXFragmentRootWin>(hwnd(), root); - Microsoft::WRL::ComPtr<IRawElementProviderSimple> root_uia; ax_fragment_root_->GetNativeViewAccessible()->QueryInterface( IID_PPV_ARGS(&root_uia)); @@ -554,6 +540,34 @@ DestroyAnimationObserver(); } +gfx::NativeViewAccessible +LegacyRenderWidgetHostHWND::GetOrCreateWindowRootAccessible() { + RenderWidgetHostImpl* rwhi = + RenderWidgetHostImpl::From(host_->GetRenderWidgetHost()); + if (!rwhi) + return nullptr; + + BrowserAccessibilityManagerWin* manager = + static_cast<BrowserAccessibilityManagerWin*>( + rwhi->GetOrCreateRootBrowserAccessibilityManager()); + if (!manager || !manager->GetRoot()) + return nullptr; + + BrowserAccessibilityComWin* root = + ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM(); + + if (::switches::IsExperimentalAccessibilityPlatformUIAEnabled()) { + if (!ax_fragment_root_) { + ax_fragment_root_ = std::make_unique<ui::AXFragmentRootWin>(hwnd(), root); + ax_fragment_root_->SetParent(host_->GetParentNativeViewAccessible()); + } + + return ax_fragment_root_->GetNativeViewAccessible(); + } + + return root->GetNativeViewAccessible(); +} + void LegacyRenderWidgetHostHWND::CreateAnimationObserver() { DCHECK(!compositor_animation_observer_); DCHECK(host_);
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h index 3be08b1..ec2ec68 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.h +++ b/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -16,6 +16,7 @@ #include "content/common/content_export.h" #include "ui/compositor/compositor_animation_observer.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/native_widget_types.h" namespace ui { class AXFragmentRootWin; @@ -128,6 +129,9 @@ // gesturing on touchpad. void PollForNextEvent(); + // Return the root accessible object for either MSAA or UI Automation. + gfx::NativeViewAccessible GetOrCreateWindowRootAccessible(); + protected: void OnFinalMessage(HWND hwnd) override;
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc index 4caf7d5..7c551b5c 100644 --- a/content/browser/renderer_host/render_process_host_browsertest.cc +++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -416,7 +416,9 @@ GURL test_url = embedded_test_server()->GetURL("/simple_page.html"); BrowserContext* browser_context = ShellContentBrowserClient::Get()->browser_context(); - GURL test_site = SiteInstance::GetSiteForURL(browser_context, test_url); + scoped_refptr<SiteInstance> test_site_instance = + SiteInstance::Create(browser_context)->GetRelatedSiteInstance(test_url); + GURL test_site = test_site_instance->GetSiteURL(); CustomStoragePartitionForSomeSites modified_client(test_site); ContentBrowserClient* old_client = SetBrowserClientForTesting(&modified_client);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index a8185e63..92a6bcde 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1608,13 +1608,6 @@ << "RenderProcessHostImpl is destroyed by something other than itself"; #endif - if (render_frame_message_filter_) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&RenderFrameMessageFilter::ClearResourceContext, - render_frame_message_filter_)); - } - // Make sure to clean up the in-process renderer before the channel, otherwise // it may still run and have its IPCs fail, causing asserts. in_process_renderer_.reset(); @@ -2647,6 +2640,11 @@ ChildProcessImportance RenderProcessHostImpl::GetEffectiveImportance() { return effective_importance_; } + +void RenderProcessHostImpl::DumpProcessStack() { + if (child_process_launcher_) + child_process_launcher_->DumpProcessStack(); +} #endif RendererAudioOutputStreamFactoryContext* @@ -2844,7 +2842,7 @@ if (!SiteInstanceImpl::IsOriginLockASite(lock_url)) return; - GetRendererInterface()->SetIsLockedToSite(); + GetRendererInterface()->SetIsLockedToSite(lock_url); } bool RenderProcessHostImpl::IsForGuestsOnly() { @@ -3493,6 +3491,19 @@ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); deleting_soon_ = true; + if (render_frame_message_filter_) { + // RenderFrameMessageFilter is refcounted and can outlive the + // ResourceContext. If the BrowserContext is shutting down, after + // RenderProcessHostImpl cleanup a task will be posted to the IO thread + // that destroys the ResourceContext. Therefore the ClearResourceContext + // task must be posted now to ensure it gets ahead of the destruction of + // the ResourceContext in the IOThread sequence. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&RenderFrameMessageFilter::ClearResourceContext, + render_frame_message_filter_)); + } + // Destroy all mojo bindings and IPC channels that can cause calls to this // object, to avoid method invocations that trigger usages of profile. ResetIPC();
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 5b1f0474..a746e1d 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -185,6 +185,7 @@ void RemovePriorityClient(PriorityClient* priority_client) override; #if defined(OS_ANDROID) ChildProcessImportance GetEffectiveImportance() override; + void DumpProcessStack() override; #endif void SetSuddenTerminationAllowed(bool enabled) override; bool SuddenTerminationAllowed() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index c272f6a..cbee55a 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -569,10 +569,15 @@ aura::WindowTreeHost* window_host = window_->GetHost(); if (!window_host) return static_cast<gfx::NativeViewAccessible>(NULL); + + if (legacy_render_widget_host_HWND_) + return legacy_render_widget_host_HWND_->GetOrCreateWindowRootAccessible(); + BrowserAccessibilityManager* manager = host()->GetOrCreateRootBrowserAccessibilityManager(); if (manager) return ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM(); + #elif defined(USE_X11) BrowserAccessibilityManager* manager = host()->GetOrCreateRootBrowserAccessibilityManager(); @@ -880,6 +885,16 @@ legacy_render_widget_host_HWND_ = nullptr; legacy_window_destroyed_ = true; } + +gfx::NativeViewAccessible +RenderWidgetHostViewAura::GetParentNativeViewAccessible() { + if (window_->parent()) { + return window_->parent()->GetProperty( + aura::client::kParentNativeViewAccessibleKey); + } + + return nullptr; +} #endif void RenderWidgetHostViewAura::DidCreateNewRendererCompositorFrameSink(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 126be50..a2dedc2 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -307,6 +307,8 @@ // Notification that the LegacyRenderWidgetHostHWND was destroyed. void OnLegacyWindowDestroyed(); + + gfx::NativeViewAccessible GetParentNativeViewAccessible(); #endif // Method to indicate if this instance is shutting down or closing. @@ -371,12 +373,14 @@ private: friend class DelegatedFrameHostClientAura; + friend class FakeRenderWidgetHostViewAura; friend class InputMethodAuraTestBase; friend class RenderWidgetHostViewAuraTest; friend class RenderWidgetHostViewAuraBrowserTest; friend class RenderWidgetHostViewAuraCopyRequestTest; friend class TestInputMethodObserver; #if defined(OS_WIN) + friend class AccessibilityTreeLinkageWinBrowserTest; friend class DirectManipulationBrowserTest; #endif FRIEND_TEST_ALL_PREFIXES(InputMethodResultAuraTest,
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 5281c7b..4afd0dbb 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -383,8 +383,9 @@ // This is a test for crbug.com/312016. It tries to create two RenderWidgetHosts // with the same process and routing ids, which causes a collision. It is almost // identical to the AttemptDuplicateRenderViewHost test case. +// Crashes on all platforms. http://crbug.com/939338 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, - AttemptDuplicateRenderWidgetHost) { + DISABLED_AttemptDuplicateRenderWidgetHost) { int duplicate_routing_id = MSG_ROUTING_NONE; RenderFrameHostImpl* pending_rfh = PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 0fbce527..fa59552 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -132,7 +132,7 @@ } void SetSchedulerKeepActive(bool keep_active) override { NOTREACHED(); } void ProcessPurgeAndSuspend() override { NOTREACHED(); } - void SetIsLockedToSite() override { NOTREACHED(); } + void SetIsLockedToSite(const GURL& lock_url) override { NOTREACHED(); } void EnableV8LowMemoryMode() override { NOTREACHED(); } EmbeddedWorkerTestHelper* helper_;
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index 1836ca82..09e5c2a 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -77,7 +77,6 @@ #include "net/cert/cert_status_flags.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_response_info.h" -#include "net/log/net_log_with_source.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" @@ -939,8 +938,7 @@ request->method = "GET"; fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>( std::move(request), resource_type, std::string() /* client_id */, - version_, net::NetLogWithSource(), std::move(prepare_callback), - std::move(fetch_callback)); + version_, std::move(prepare_callback), std::move(fetch_callback)); fetch_dispatcher_->Run(); }
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index e6785f1..f307891 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -43,8 +43,6 @@ #include "net/base/request_priority.h" #include "net/http/http_util.h" #include "net/log/net_log.h" -#include "net/log/net_log_capture_mode.h" -#include "net/log/net_log_event_type.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/features.h" @@ -239,34 +237,6 @@ } } -std::unique_ptr<base::Value> NetLogServiceWorkerStatusCallback( - blink::ServiceWorkerStatusCode status, - net::NetLogCaptureMode) { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); - dict->SetString("status", blink::ServiceWorkerStatusToString(status)); - return std::move(dict); -} - -std::unique_ptr<base::Value> NetLogFetchEventCallback( - blink::ServiceWorkerStatusCode status, - ServiceWorkerFetchDispatcher::FetchEventResult result, - net::NetLogCaptureMode) { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); - dict->SetString("status", blink::ServiceWorkerStatusToString(status)); - dict->SetBoolean( - "has_response", - result == ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse); - return std::move(dict); -} - -void EndNetLogEventWithServiceWorkerStatus( - const net::NetLogWithSource& net_log, - net::NetLogEventType type, - blink::ServiceWorkerStatusCode status) { - net_log.EndEvent(type, - base::Bind(&NetLogServiceWorkerStatusCallback, status)); -} - const net::NetworkTrafficAnnotationTag kNavigationPreloadTrafficAnnotation = net::DefineNetworkTrafficAnnotation("service_worker_navigation_preload", R"( @@ -495,14 +465,12 @@ ResourceType resource_type, const std::string& client_id, scoped_refptr<ServiceWorkerVersion> version, - const net::NetLogWithSource& net_log, base::OnceClosure prepare_callback, FetchCallback fetch_callback) : request_(std::move(request)), client_id_(client_id), version_(std::move(version)), resource_type_(resource_type), - net_log_(net_log), prepare_callback_(std::move(prepare_callback)), fetch_callback_(std::move(fetch_callback)), did_complete_(false), @@ -511,17 +479,9 @@ if (blink::ServiceWorkerUtils::IsServicificationEnabled()) DCHECK(!request_->blob); #endif // DCHECK_IS_ON() - net_log_.BeginEvent(net::NetLogEventType::SERVICE_WORKER_DISPATCH_FETCH_EVENT, - net::NetLog::StringCallback( - "event_type", ServiceWorkerMetrics::EventTypeToString( - GetEventType()))); } -ServiceWorkerFetchDispatcher::~ServiceWorkerFetchDispatcher() { - if (!did_complete_) - net_log_.EndEvent( - net::NetLogEventType::SERVICE_WORKER_DISPATCH_FETCH_EVENT); -} +ServiceWorkerFetchDispatcher::~ServiceWorkerFetchDispatcher() = default; void ServiceWorkerFetchDispatcher::Run() { DCHECK(version_->status() == ServiceWorkerVersion::ACTIVATING || @@ -529,8 +489,6 @@ << version_->status(); if (version_->status() == ServiceWorkerVersion::ACTIVATING) { - net_log_.BeginEvent( - net::NetLogEventType::SERVICE_WORKER_WAIT_FOR_ACTIVATION); version_->RegisterStatusChangeCallback( base::BindOnce(&ServiceWorkerFetchDispatcher::DidWaitForActivation, weak_factory_.GetWeakPtr())); @@ -540,7 +498,6 @@ } void ServiceWorkerFetchDispatcher::DidWaitForActivation() { - net_log_.EndEvent(net::NetLogEventType::SERVICE_WORKER_WAIT_FOR_ACTIVATION); StartWorker(); } @@ -558,7 +515,6 @@ return; } - net_log_.BeginEvent(net::NetLogEventType::SERVICE_WORKER_START_WORKER); version_->RunAfterStartWorker( GetEventType(), base::BindOnce(&ServiceWorkerFetchDispatcher::DidStartWorker, @@ -568,12 +524,9 @@ void ServiceWorkerFetchDispatcher::DidStartWorker( blink::ServiceWorkerStatusCode status) { if (status != blink::ServiceWorkerStatusCode::kOk) { - EndNetLogEventWithServiceWorkerStatus( - net_log_, net::NetLogEventType::SERVICE_WORKER_START_WORKER, status); DidFail(status); return; } - net_log_.EndEvent(net::NetLogEventType::SERVICE_WORKER_START_WORKER); DispatchFetchEvent(); } @@ -590,7 +543,6 @@ // Run callback to say that the fetch event will be dispatched. DCHECK(prepare_callback_); std::move(prepare_callback_).Run(); - net_log_.BeginEvent(net::NetLogEventType::SERVICE_WORKER_FETCH_EVENT); // Set up for receiving the response. blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_ptr; @@ -636,8 +588,6 @@ void ServiceWorkerFetchDispatcher::DidFailToDispatch( std::unique_ptr<ResponseCallback> response_callback, blink::ServiceWorkerStatusCode status) { - EndNetLogEventWithServiceWorkerStatus( - net_log_, net::NetLogEventType::SERVICE_WORKER_FETCH_EVENT, status); DidFail(status); } @@ -655,7 +605,6 @@ blink::mojom::FetchAPIResponsePtr response, blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, blink::mojom::ServiceWorkerFetchEventTimingPtr timing) { - net_log_.EndEvent(net::NetLogEventType::SERVICE_WORKER_FETCH_EVENT); Complete(blink::ServiceWorkerStatusCode::kOk, fetch_result, std::move(response), std::move(body_as_stream), std::move(timing)); } @@ -669,10 +618,6 @@ DCHECK(fetch_callback_); did_complete_ = true; - net_log_.EndEvent( - net::NetLogEventType::SERVICE_WORKER_DISPATCH_FETCH_EVENT, - base::Bind(&NetLogFetchEventCallback, status, fetch_result)); - std::move(fetch_callback_) .Run(status, fetch_result, std::move(response), std::move(body_as_stream), std::move(timing), version_);
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h index 9c169b10..a5745ab0 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.h +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -18,7 +18,6 @@ #include "content/common/content_export.h" #include "content/public/common/resource_type.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "net/log/net_log_with_source.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" @@ -59,7 +58,6 @@ ResourceType resource_type, const std::string& client_id, scoped_refptr<ServiceWorkerVersion> version, - const net::NetLogWithSource& net_log, base::OnceClosure prepare_callback, FetchCallback fetch_callback); ~ServiceWorkerFetchDispatcher(); @@ -122,7 +120,6 @@ std::string client_id_; scoped_refptr<ServiceWorkerVersion> version_; const ResourceType resource_type_; - net::NetLogWithSource net_log_; base::OnceClosure prepare_callback_; FetchCallback fetch_callback_; bool did_complete_;
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc index ca894b5..a505f5d34 100644 --- a/content/browser/service_worker/service_worker_navigation_loader.cc +++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -243,7 +243,6 @@ blink::mojom::FetchAPIRequest::From(resource_request_), static_cast<ResourceType>(resource_request_.resource_type), provider_host_->client_uuid(), active_worker, - net::NetLogWithSource() /* TODO(scottmg): net log? */, base::BindOnce(&ServiceWorkerNavigationLoader::DidPrepareFetchEvent, weak_factory_.GetWeakPtr(), base::WrapRefCounted(active_worker),
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc index 77d7c45..05ebba7 100644 --- a/content/browser/service_worker/service_worker_request_handler.cc +++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -26,7 +26,6 @@ #include "ipc/ipc_message.h" #include "net/base/url_util.h" #include "net/url_request/url_request.h" -#include "net/url_request/url_request_interceptor.h" #include "services/network/public/cpp/resource_request_body.h" #include "storage/browser/blob/blob_storage_context.h" #include "third_party/blink/public/common/service_worker/service_worker_utils.h" @@ -35,28 +34,6 @@ namespace { -class ServiceWorkerRequestInterceptor - : public net::URLRequestInterceptor { - public: - explicit ServiceWorkerRequestInterceptor(ResourceContext* resource_context) - : resource_context_(resource_context) {} - ~ServiceWorkerRequestInterceptor() override {} - net::URLRequestJob* MaybeInterceptRequest( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - ServiceWorkerRequestHandler* handler = - ServiceWorkerRequestHandler::GetHandler(request); - if (!handler) - return nullptr; - return handler->MaybeCreateJob( - request, network_delegate, resource_context_); - } - - private: - ResourceContext* resource_context_; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestInterceptor); -}; - bool SchemeMaySupportRedirectingToHTTPS(const GURL& url) { #if defined(OS_CHROMEOS) return url.SchemeIs(kExternalFileScheme); @@ -71,69 +48,6 @@ int ServiceWorkerRequestHandler::user_data_key_; // static -void ServiceWorkerRequestHandler::InitializeForNavigation( - net::URLRequest* request, - ServiceWorkerNavigationHandleCore* navigation_handle_core, - storage::BlobStorageContext* blob_storage_context, - bool skip_service_worker, - ResourceType resource_type, - blink::mojom::RequestContextType request_context_type, - network::mojom::RequestContextFrameType frame_type, - bool is_parent_frame_secure, - scoped_refptr<network::ResourceRequestBody> body, - base::RepeatingCallback<WebContents*()> web_contents_getter) { - // Only create a handler when there is a ServiceWorkerNavigationHandlerCore - // to take ownership of a pre-created SeviceWorkerProviderHost. - if (!navigation_handle_core) - return; - - // This is the legacy path used by non-NetworkService and - // non-S13nServiceWorker. The NetworkService/S13nServiceWorker path is - // InitializeForNavigationNetworkService(). - // - // This function can still be called with a null navigation_handle_core by - // ResourceDispatcherHostImpl::BeginNavigationRequest when S13nSW is on and - // NetworkService is off, so this DCHECK must be after the null check above. - DCHECK(!blink::ServiceWorkerUtils::IsServicificationEnabled()); - - // Create the handler even for insecure HTTP since it's used in the - // case of redirect to HTTPS. - if (!request->url().SchemeIsHTTPOrHTTPS() && - !OriginCanAccessServiceWorkers(request->url()) && - !SchemeMaySupportRedirectingToHTTPS(request->url())) { - return; - } - - if (!navigation_handle_core->context_wrapper()) - return; - ServiceWorkerContextCore* context = - navigation_handle_core->context_wrapper()->context(); - if (!context) - return; - - // Initialize the SWProviderHost. - base::WeakPtr<ServiceWorkerProviderHost> provider_host = - ServiceWorkerProviderHost::PreCreateNavigationHost( - context->AsWeakPtr(), is_parent_frame_secure, - std::move(web_contents_getter)); - - std::unique_ptr<ServiceWorkerRequestHandler> handler( - provider_host->CreateRequestHandler( - network::mojom::FetchRequestMode::kNavigate, - network::mojom::FetchCredentialsMode::kInclude, - network::mojom::FetchRedirectMode::kManual, - std::string() /* integrity */, false /* keepalive */, resource_type, - request_context_type, frame_type, blob_storage_context->AsWeakPtr(), - body, skip_service_worker)); - if (handler) - request->SetUserData(&user_data_key_, std::move(handler)); - - navigation_handle_core->DidPreCreateProviderHost( - provider_host->provider_id()); -} - -// S13nServiceWorker: -// static std::unique_ptr<NavigationLoaderInterceptor> ServiceWorkerRequestHandler::InitializeForNavigationNetworkService( const GURL& url, @@ -279,14 +193,6 @@ } // static -std::unique_ptr<net::URLRequestInterceptor> -ServiceWorkerRequestHandler::CreateInterceptor( - ResourceContext* resource_context) { - return std::unique_ptr<net::URLRequestInterceptor>( - new ServiceWorkerRequestInterceptor(resource_context)); -} - -// static bool ServiceWorkerRequestHandler::IsControlledByServiceWorker( const net::URLRequest* request) { ServiceWorkerRequestHandler* handler = GetHandler(request);
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h index 4d100aa..9e723d58 100644 --- a/content/browser/service_worker/service_worker_request_handler.h +++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -25,7 +25,6 @@ namespace net { class NetworkDelegate; class URLRequest; -class URLRequestInterceptor; } namespace network { @@ -51,24 +50,10 @@ : public base::SupportsUserData::Data, public NavigationLoaderInterceptor { public: - // PlzNavigate - // Attaches a newly created handler if the given |request| needs to be handled - // by ServiceWorker. - static void InitializeForNavigation( - net::URLRequest* request, - ServiceWorkerNavigationHandleCore* navigation_handle_core, - storage::BlobStorageContext* blob_storage_context, - bool skip_service_worker, - ResourceType resource_type, - blink::mojom::RequestContextType request_context_type, - network::mojom::RequestContextFrameType frame_type, - bool is_parent_frame_secure, - scoped_refptr<network::ResourceRequestBody> body, - base::RepeatingCallback<WebContents*()> web_contents_getter); - - // S13nServiceWorker: - // Same as InitializeForNavigation() but instead of attaching to a URLRequest, - // just creates a NavigationLoaderInterceptor and returns it. + // Returns a loader interceptor for a navigation. May return nullptr + // if the navigation cannot use service workers. + // TODO(falken): Rename to InitializeForNavigation since this also is called + // when NetworkService is disabled. static std::unique_ptr<NavigationLoaderInterceptor> InitializeForNavigationNetworkService( const GURL& url, @@ -116,10 +101,6 @@ static ServiceWorkerRequestHandler* GetHandler( const net::URLRequest* request); - // Creates a protocol interceptor for ServiceWorker. - static std::unique_ptr<net::URLRequestInterceptor> CreateInterceptor( - ResourceContext* resource_context); - // Returns true if the request falls into the scope of a ServiceWorker. // It's only reliable after the ServiceWorkerRequestHandler MaybeCreateJob // method runs to completion for this request. The AppCache handler uses
diff --git a/content/browser/service_worker/service_worker_request_handler_unittest.cc b/content/browser/service_worker/service_worker_request_handler_unittest.cc index a942079..ceac781f 100644 --- a/content/browser/service_worker/service_worker_request_handler_unittest.cc +++ b/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -132,36 +132,6 @@ void InitializeHandlerForNavigationSimpleTest(const std::string& url, bool expected_handler_created) { - bool handler_created = false; - if (blink::ServiceWorkerUtils::IsServicificationEnabled()) { - handler_created = InitializeHandlerForNavigationNetworkService( - url, expected_handler_created); - } else { - handler_created = InitializeHandlerForNavigationNonNetworkService( - url, expected_handler_created); - } - EXPECT_EQ(expected_handler_created, handler_created); - } - - bool InitializeHandlerForNavigationNonNetworkService( - const std::string& url, - bool expected_handler_created) { - std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core = - CreateNavigationHandleCore(helper_->context_wrapper()); - std::unique_ptr<net::URLRequest> request = CreateRequest(url, "GET"); - ServiceWorkerRequestHandler::InitializeForNavigation( - request.get(), navigation_handle_core.get(), &blob_storage_context_, - false /* skip_service_worker */, RESOURCE_TYPE_MAIN_FRAME, - blink::mojom::RequestContextType::HYPERLINK, - network::mojom::RequestContextFrameType::kTopLevel, - true /* is_parent_frame_secure */, nullptr /* body */, - base::RepeatingCallback<WebContents*(void)>()); - return !!GetHandler(request.get()); - } - - bool InitializeHandlerForNavigationNetworkService( - const std::string& url, - bool expected_handler_created) { std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core = CreateNavigationHandleCore(helper_->context_wrapper()); base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host; @@ -175,7 +145,7 @@ true /* is_parent_frame_secure */, nullptr /* body */, base::RepeatingCallback<WebContents*(void)>(), &service_worker_provider_host); - return !!interceptor.get(); + EXPECT_EQ(expected_handler_created, !!interceptor.get()); } TestBrowserThreadBundle browser_thread_bundle_;
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc index be01af49..31f10bda 100644 --- a/content/browser/service_worker/service_worker_url_request_job.cc +++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -852,7 +852,6 @@ fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>( std::move(fetch_api_request), resource_type_, provider_host_->client_uuid(), base::WrapRefCounted(active_worker), - request()->net_log(), base::BindOnce(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent, weak_factory_.GetWeakPtr(), base::WrapRefCounted(active_worker)),
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc index bbeebe73..9dcff48c 100644 --- a/content/browser/site_instance_impl.cc +++ b/content/browser/site_instance_impl.cc
@@ -13,6 +13,7 @@ #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/frame_host/debug_urls.h" #include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/isolated_origin_util.h" #include "content/browser/isolation_context.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/storage_partition_impl.h" @@ -75,7 +76,8 @@ // This will create a new SiteInstance and BrowsingInstance. scoped_refptr<BrowsingInstance> instance( new BrowsingInstance(browser_context)); - return instance->GetSiteInstanceForURL(url); + return instance->GetSiteInstanceForURL(url, + /* allow_default_instance */ false); } // static @@ -113,6 +115,10 @@ return browsing_instance_->default_process(); } +bool SiteInstanceImpl::IsDefaultSiteInstance() { + return browsing_instance_->IsDefaultSiteInstance(this); +} + void SiteInstanceImpl::MaybeSetBrowsingInstanceDefaultProcess() { if (!base::FeatureList::IsEnabled( features::kProcessSharingWithStrictSiteInstances)) { @@ -225,12 +231,9 @@ // URL is invalid. has_site_ = true; BrowserContext* browser_context = browsing_instance_->browser_context(); - site_ = GetSiteForURL(BrowserOrResourceContext(browser_context), - GetIsolationContext(), url, - true /* should_use_effective_urls */); original_url_ = url; - lock_url_ = DetermineProcessLockURL(BrowserOrResourceContext(browser_context), - GetIsolationContext(), url); + browsing_instance_->GetSiteAndLockForURL( + url, /* allow_default_instance */ false, &site_, &lock_url_); // Now that we have a site, register it with the BrowsingInstance. This // ensures that we won't create another SiteInstance for this site within @@ -271,7 +274,8 @@ scoped_refptr<SiteInstance> SiteInstanceImpl::GetRelatedSiteInstance( const GURL& url) { - return browsing_instance_->GetSiteInstanceForURL(url); + return browsing_instance_->GetSiteInstanceForURL( + url, /* allow_default_instance */ true); } bool SiteInstanceImpl::IsRelatedSiteInstance(const SiteInstance* instance) { @@ -310,11 +314,14 @@ // If the site URL is an extension (e.g., for hosted apps or WebUI) but the // process is not (or vice versa), make sure we notice and fix it. - GURL site_url = SiteInstanceImpl::GetSiteForURL( - browsing_instance_->browser_context(), GetIsolationContext(), url); - GURL origin_lock = DetermineProcessLockURL( - BrowserOrResourceContext(browsing_instance_->browser_context()), - GetIsolationContext(), url); + GURL site_url; + GURL origin_lock; + + // Note: This call must return information that is identical to what + // would be reported in the SiteInstance returned by + // GetRelatedSiteInstance(url). + browsing_instance_->GetSiteAndLockForURL( + url, /* allow_default_instance */ true, &site_url, &origin_lock); return !RenderProcessHostImpl::IsSuitableHost( GetProcess(), browsing_instance_->browser_context(), GetIsolationContext(), site_url, origin_lock); @@ -810,4 +817,27 @@ } } +// static +void SiteInstance::StartIsolatingSite(BrowserContext* context, + const GURL& url) { + if (!SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled()) + return; + + // Ignore attempts to isolate origins that are not supported. Do this here + // instead of relying on AddIsolatedOrigins()'s internal validation, to avoid + // the runtime warning generated by the latter. + url::Origin origin(url::Origin::Create(url)); + if (!IsolatedOriginUtil::IsValidIsolatedOrigin(origin)) + return; + + // Convert |url| to a site, to avoid breaking document.domain. Note that + // this doesn't use effective URL resolution or other special cases from + // GetSiteForURL() and simply converts |origin| to a scheme and eTLD+1. + GURL site(SiteInstanceImpl::GetSiteForOrigin(origin)); + + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + policy->AddIsolatedOrigins({url::Origin::Create(site)}, context); +} + } // namespace content
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h index 1acc3ef..5889208a 100644 --- a/content/browser/site_instance_impl.h +++ b/content/browser/site_instance_impl.h
@@ -283,6 +283,9 @@ // the BrowsingInstance's default process. RenderProcessHost* GetDefaultProcessIfUsable(); + // Returns true if this object was constructed as a default site instance. + bool IsDefaultSiteInstance(); + private: friend class BrowsingInstance; friend class SiteInstanceTestBrowserClient;
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc index 33f16dd..14ae9f0 100644 --- a/content/browser/site_instance_impl_unittest.cc +++ b/content/browser/site_instance_impl_unittest.cc
@@ -470,9 +470,14 @@ GURL("https://bar.com/")); scoped_refptr<SiteInstance> site_instance = bar_site_instance->GetRelatedSiteInstance(test_url); - EXPECT_EQ(expected_app_site_url, site_instance->GetSiteURL()); - EXPECT_EQ(nonapp_site_url, - static_cast<SiteInstanceImpl*>(site_instance.get())->lock_url()); + auto* site_instance_impl = + static_cast<SiteInstanceImpl*>(site_instance.get()); + if (AreAllSitesIsolatedForTesting()) { + EXPECT_EQ(expected_app_site_url, site_instance->GetSiteURL()); + EXPECT_EQ(nonapp_site_url, site_instance_impl->lock_url()); + } else { + EXPECT_TRUE(site_instance_impl->IsDefaultSiteInstance()); + } } // New SiteInstance with a lazily assigned site URL. @@ -566,14 +571,14 @@ const GURL url_a1("http://www.google.com/1.html"); scoped_refptr<SiteInstanceImpl> site_instance_a1( - browsing_instance->GetSiteInstanceForURL(url_a1)); + browsing_instance->GetSiteInstanceForURL(url_a1, false)); EXPECT_TRUE(site_instance_a1.get() != nullptr); // A separate site should create a separate SiteInstance. const GURL url_b1("http://www.yahoo.com/"); scoped_refptr<SiteInstanceImpl> site_instance_b1( - browsing_instance->GetSiteInstanceForURL(url_b1)); + browsing_instance->GetSiteInstanceForURL(url_b1, false)); EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get())); @@ -585,7 +590,7 @@ // A second visit to the original site should return the same SiteInstance. const GURL url_a2("http://www.google.com/2.html"); EXPECT_EQ(site_instance_a1.get(), - browsing_instance->GetSiteInstanceForURL(url_a2)); + browsing_instance->GetSiteInstanceForURL(url_a2, false)); EXPECT_EQ(site_instance_a1.get(), site_instance_a1->GetRelatedSiteInstance(url_a2)); @@ -595,7 +600,7 @@ new BrowsingInstance(browser_context.get()); // Ensure the new SiteInstance is ref counted so that it gets deleted. scoped_refptr<SiteInstanceImpl> site_instance_a2_2( - browsing_instance2->GetSiteInstanceForURL(url_a2)); + browsing_instance2->GetSiteInstanceForURL(url_a2, false)); EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get()); EXPECT_FALSE( site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2.get())); @@ -638,14 +643,14 @@ const GURL url_a1("http://www.google.com/1.html"); scoped_refptr<SiteInstanceImpl> site_instance_a1( - browsing_instance->GetSiteInstanceForURL(url_a1)); + browsing_instance->GetSiteInstanceForURL(url_a1, false)); EXPECT_TRUE(site_instance_a1.get() != nullptr); std::unique_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess()); // A separate site should create a separate SiteInstance. const GURL url_b1("http://www.yahoo.com/"); scoped_refptr<SiteInstanceImpl> site_instance_b1( - browsing_instance->GetSiteInstanceForURL(url_b1)); + browsing_instance->GetSiteInstanceForURL(url_b1, false)); EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get())); @@ -657,7 +662,7 @@ // A second visit to the original site should return the same SiteInstance. const GURL url_a2("http://www.google.com/2.html"); EXPECT_EQ(site_instance_a1.get(), - browsing_instance->GetSiteInstanceForURL(url_a2)); + browsing_instance->GetSiteInstanceForURL(url_a2, false)); EXPECT_EQ(site_instance_a1.get(), site_instance_a1->GetRelatedSiteInstance(url_a2)); @@ -666,7 +671,7 @@ BrowsingInstance* browsing_instance2 = new BrowsingInstance(browser_context.get()); scoped_refptr<SiteInstanceImpl> site_instance_a1_2( - browsing_instance2->GetSiteInstanceForURL(url_a1)); + browsing_instance2->GetSiteInstanceForURL(url_a1, false)); EXPECT_TRUE(site_instance_a1.get() != nullptr); EXPECT_NE(site_instance_a1.get(), site_instance_a1_2.get()); EXPECT_EQ(process_a1.get(), site_instance_a1_2->GetProcess()); @@ -678,7 +683,7 @@ BrowsingInstance* browsing_instance3 = new BrowsingInstance(browser_context2.get()); scoped_refptr<SiteInstanceImpl> site_instance_a2_3( - browsing_instance3->GetSiteInstanceForURL(url_a2)); + browsing_instance3->GetSiteInstanceForURL(url_a2, false)); EXPECT_TRUE(site_instance_a2_3.get() != nullptr); std::unique_ptr<RenderProcessHost> process_a2_3( site_instance_a2_3->GetProcess()); @@ -1230,10 +1235,14 @@ GURL("https://bar.com/")); scoped_refptr<SiteInstance> site_instance = bar_site_instance->GetRelatedSiteInstance(original_url); - EXPECT_EQ(expected_site_url, site_instance->GetSiteURL()); - EXPECT_EQ( - original_url, - static_cast<SiteInstanceImpl*>(site_instance.get())->original_url()); + auto* site_instance_impl = + static_cast<SiteInstanceImpl*>(site_instance.get()); + if (AreAllSitesIsolatedForTesting()) { + EXPECT_EQ(expected_site_url, site_instance->GetSiteURL()); + EXPECT_EQ(original_url, site_instance_impl->original_url()); + } else { + EXPECT_TRUE(site_instance_impl->IsDefaultSiteInstance()); + } } // New SiteInstance with a lazily assigned site URL. @@ -1263,4 +1272,30 @@ GURL("http://user:pass@google.com:99/foo;bar?q=a#ref"))); } +TEST_F(SiteInstanceTest, StartIsolatingSite) { + IsolationContext isolation_context(context()); + auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); + + // StartIsolatingSite() should convert the URL to a site before isolating it. + SiteInstance::StartIsolatingSite(context(), + GURL("http://bar.foo.com/foo/bar.html")); + EXPECT_TRUE(IsIsolatedOrigin(GURL("http://foo.com"))); + SiteInstance::StartIsolatingSite(context(), GURL("https://a.b.c.com:8000/")); + EXPECT_TRUE(IsIsolatedOrigin(GURL("https://c.com"))); + SiteInstance::StartIsolatingSite(context(), + GURL("http://bar.com/foo/bar.html")); + EXPECT_TRUE(IsIsolatedOrigin(GURL("http://bar.com"))); + + // Attempts to isolate an unsupported isolated origin should be ignored. + GURL data_url("data:,"); + GURL blank_url(url::kAboutBlankURL); + SiteInstance::StartIsolatingSite(context(), data_url); + SiteInstance::StartIsolatingSite(context(), blank_url); + EXPECT_FALSE(IsIsolatedOrigin(data_url)); + EXPECT_FALSE(IsIsolatedOrigin(blank_url)); + + // Cleanup. + policy->RemoveIsolatedOriginsForBrowserContext(*context()); +} + } // namespace content
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index ca6a967..84e8ebd2 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -3573,6 +3573,125 @@ EXPECT_TRUE(interceptor->Capturing()); } +IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, + CrossProcessMousePointerCapture) { + GURL main_url(embedded_test_server()->GetURL( + "/frame_tree/page_with_iframe_in_div.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + RenderFrameSubmissionObserver render_frame_submission_observer( + shell()->web_contents()); + + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + FrameTreeNode* child_node = root->child_at(0); + ASSERT_EQ( + " Site A ------------ proxies for B\n" + " +--Site B ------- proxies for A\n" + "Where A = http://127.0.0.1/\n" + " B = http://bar.com/", + DepictFrameTree(root)); + + ASSERT_TRUE(ExecuteScript(root, + " document.addEventListener('pointerdown', (e) => {" + " e.target.setPointerCapture(e.pointerId);" + "});")); + + // Create listeners for mouse events. + RenderWidgetHostMouseEventMonitor main_frame_monitor( + root->current_frame_host()->GetRenderWidgetHost()); + RenderWidgetHostMouseEventMonitor child_frame_monitor( + child_node->current_frame_host()->GetRenderWidgetHost()); + + WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host()); + + RenderWidgetHostInputEventRouter* router = + web_contents()->GetInputEventRouter(); + + RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( + root->current_frame_host()->GetRenderWidgetHost()->GetView()); + RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>( + child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); + + scoped_refptr<SetMouseCaptureInterceptor> root_interceptor = + new SetMouseCaptureInterceptor(static_cast<RenderWidgetHostImpl*>( + root->current_frame_host()->GetRenderWidgetHost())); + + // Target MouseDown to main frame. + blink::WebMouseEvent mouse_event( + blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); + mouse_event.button = blink::WebPointerProperties::Button::kLeft; + mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown); + mouse_event.pointer_type = blink::WebPointerProperties::PointerType::kMouse; + SetWebEventPositions(&mouse_event, gfx::Point(1, 1), root_view); + mouse_event.click_count = 1; + main_frame_monitor.ResetEventReceived(); + child_frame_monitor.ResetEventReceived(); + RouteMouseEventAndWaitUntilDispatch(router, root_view, root_view, + &mouse_event); + + EXPECT_TRUE(main_frame_monitor.EventWasReceived()); + EXPECT_FALSE(child_frame_monitor.EventWasReceived()); + // Wait for the mouse capture message. + root_interceptor->Wait(); + EXPECT_TRUE(root_interceptor->Capturing()); + base::RunLoop().RunUntilIdle(); + + // Target MouseMove at child frame. The main frame is now capturing input, + // so it should receive the event instead. + float scale_factor = + render_frame_submission_observer.LastRenderFrameMetadata() + .page_scale_factor; + gfx::Rect bounds = child_view->GetViewBounds(); + int child_frame_target_x = gfx::ToCeiledInt( + (bounds.x() - root_view->GetViewBounds().x() + 5) * scale_factor); + int child_frame_target_y = gfx::ToCeiledInt( + (bounds.y() - root_view->GetViewBounds().y() + 5) * scale_factor); + mouse_event.SetType(blink::WebInputEvent::kMouseMove); + mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown); + + SetWebEventPositions(&mouse_event, + gfx::Point(child_frame_target_x, child_frame_target_y), + root_view); + + main_frame_monitor.ResetEventReceived(); + child_frame_monitor.ResetEventReceived(); + RouteMouseEventAndWaitUntilDispatch(router, root_view, root_view, + &mouse_event); + + EXPECT_TRUE(main_frame_monitor.EventWasReceived()); + EXPECT_FALSE(child_frame_monitor.EventWasReceived()); + + // Add script to release capture and send a mouse move to triger it. + ASSERT_TRUE(ExecuteScript(root, + " document.addEventListener('pointermove', (e) => {" + " e.target.releasePointerCapture(e.pointerId);" + "});")); + main_frame_monitor.ResetEventReceived(); + child_frame_monitor.ResetEventReceived(); + RouteMouseEventAndWaitUntilDispatch(router, root_view, root_view, + &mouse_event); + + EXPECT_TRUE(main_frame_monitor.EventWasReceived()); + EXPECT_FALSE(child_frame_monitor.EventWasReceived()); + + // Mouse capture should be released now. + root_interceptor->Wait(); + EXPECT_FALSE(root_interceptor->Capturing()); + + // Next move event should route to child frame. + RouteMouseEventAndWaitUntilDispatch(router, root_view, child_view, + &mouse_event); + // Dispatch twice because the router generates an extra MouseLeave for the + // main frame. + main_frame_monitor.ResetEventReceived(); + child_frame_monitor.ResetEventReceived(); + RouteMouseEventAndWaitUntilDispatch(router, root_view, child_view, + &mouse_event); + EXPECT_FALSE(main_frame_monitor.EventWasReceived()); + EXPECT_TRUE(child_frame_monitor.EventWasReceived()); +} + // There are no cursors on Android. #if !defined(OS_ANDROID) class CursorMessageFilter : public content::BrowserMessageFilter {
diff --git a/content/browser/speech/mock_tts_controller.cc b/content/browser/speech/mock_tts_controller.cc index ac6fdd6..2d7c0dc 100644 --- a/content/browser/speech/mock_tts_controller.cc +++ b/content/browser/speech/mock_tts_controller.cc
@@ -30,6 +30,8 @@ void Stop() override {} + void Stop(const GURL& source_url) override {} + void Pause() override {} void Resume() override {}
diff --git a/content/browser/speech/tts_controller_impl.cc b/content/browser/speech/tts_controller_impl.cc index c47dac1f..554a2129 100644 --- a/content/browser/speech/tts_controller_impl.cc +++ b/content/browser/speech/tts_controller_impl.cc
@@ -108,9 +108,18 @@ } void TtsControllerImpl::Stop() { + Stop(GURL()); +} + +void TtsControllerImpl::Stop(const GURL& source_url) { base::RecordAction(base::UserMetricsAction("TextToSpeech.Stop")); paused_ = false; + + if (!source_url.is_empty() && current_utterance_ && + current_utterance_->GetSrcUrl().GetOrigin() != source_url.GetOrigin()) + return; + if (current_utterance_ && !current_utterance_->GetEngineId().empty()) { if (GetTtsControllerDelegate()->GetTtsEngineDelegate()) GetTtsControllerDelegate()->GetTtsEngineDelegate()->Stop(
diff --git a/content/browser/speech/tts_controller_impl.h b/content/browser/speech/tts_controller_impl.h index d959a6c..93abbdb 100644 --- a/content/browser/speech/tts_controller_impl.h +++ b/content/browser/speech/tts_controller_impl.h
@@ -42,6 +42,7 @@ bool IsSpeaking() override; void SpeakOrEnqueue(TtsUtterance* utterance) override; void Stop() override; + void Stop(const GURL& source_url) override; void Pause() override; void Resume() override; void OnTtsEvent(int utterance_id,
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index ac79b6f..4d42ad98 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc
@@ -34,7 +34,6 @@ #include "content/browser/loader/prefetch_url_loader_service.h" #include "content/browser/loader/resource_request_info_impl.h" #include "content/browser/resource_context_impl.h" -#include "content/browser/service_worker/service_worker_request_handler.h" #include "content/browser/storage_partition_impl.h" #include "content/browser/streams/stream.h" #include "content/browser/streams/stream_context.h" @@ -419,8 +418,6 @@ DevToolsURLRequestInterceptor::MaybeCreate(browser_context_); if (devtools_interceptor) request_interceptors.push_back(std::move(devtools_interceptor)); - request_interceptors.push_back(ServiceWorkerRequestHandler::CreateInterceptor( - browser_context_->GetResourceContext())); request_interceptors.push_back(std::make_unique<AppCacheInterceptor>()); bool create_request_context = true;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 58c6678..9ad7688 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1299,11 +1299,20 @@ } void WebContentsImpl::EnableWebContentsOnlyAccessibilityMode() { - if (!GetAccessibilityMode().is_mode_off()) { + // If accessibility is already enabled, we'll need to force a reset + // in order to ensure new observers of accessibility events get the + // full accessibility tree from scratch. + bool need_reset = GetAccessibilityMode().has_mode(ui::AXMode::kWebContents); + + ui::AXMode desired_mode = + GetContentClient()->browser()->GetAXModeForBrowserContext( + GetBrowserContext()); + desired_mode |= ui::kAXModeWebContentsOnly; + AddAccessibilityMode(desired_mode); + + if (need_reset) { for (RenderFrameHost* rfh : GetAllFrames()) ResetAccessibility(rfh); - } else { - AddAccessibilityMode(ui::kAXModeWebContentsOnly); } }
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc index 0c22c16..0ae9433 100644 --- a/content/browser/webauth/authenticator_impl.cc +++ b/content/browser/webauth/authenticator_impl.cc
@@ -102,6 +102,21 @@ kMaxValue = kAbandoned, }; +// The following enums correspond to UMA histograms and should not be +// reassigned. +enum class RelyingPartySecurityCheckFailure { + kOpaqueOrNonSecureOrigin = 0, + kRelyingPartyIdInvalid = 1, + kAppIdExtensionInvalid = 2, + kAppIdExtensionDomainMismatch = 3, + kMaxValue = kAppIdExtensionDomainMismatch, +}; + +void ReportSecurityCheckFailure(RelyingPartySecurityCheckFailure error) { + UMA_HISTOGRAM_ENUMERATION( + "WebAuthentication.RelyingPartySecurityCheckFailure", error); +} + bool OriginIsCryptoTokenExtension(const url::Origin& origin) { auto cryptotoken_origin = url::Origin::Create(GURL(kCryptotokenOrigin)); return cryptotoken_origin == origin; @@ -213,6 +228,8 @@ GURL appid_url = GURL(appid); if (!appid_url.is_valid() || appid_url.scheme() != url::kHttpsScheme || appid_url.scheme_piece() != origin.scheme()) { + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kAppIdExtensionInvalid); return base::nullopt; } @@ -247,6 +264,9 @@ return appid; } + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kAppIdExtensionDomainMismatch); + return base::nullopt; } @@ -615,6 +635,8 @@ relying_party_id_ = options->relying_party->id; if (!HasValidEffectiveDomain(caller_origin_)) { + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kOpaqueOrNonSecureOrigin); bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), bad_message::AUTH_INVALID_EFFECTIVE_DOMAIN); InvokeCallbackAndCleanup(std::move(callback), @@ -624,6 +646,8 @@ } if (!IsRelyingPartyIdValid(relying_party_id_, caller_origin_)) { + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kRelyingPartyIdInvalid); bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), bad_message::AUTH_INVALID_RELYING_PARTY); InvokeCallbackAndCleanup(std::move(callback), @@ -670,6 +694,10 @@ std::move(options->challenge)); } + UMA_HISTOGRAM_COUNTS_100( + "WebAuthentication.MakeCredentialExcludeCredentialsCount", + options->exclude_credentials.size()); + // U2F requests proxied from the cryptotoken extension are limited to USB // devices. const auto transports = @@ -775,6 +803,8 @@ } if (!HasValidEffectiveDomain(caller_origin_)) { + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kOpaqueOrNonSecureOrigin); bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), bad_message::AUTH_INVALID_EFFECTIVE_DOMAIN); InvokeCallbackAndCleanup(std::move(callback), @@ -784,6 +814,8 @@ } if (!IsRelyingPartyIdValid(options->relying_party_id, caller_origin_)) { + ReportSecurityCheckFailure( + RelyingPartySecurityCheckFailure::kRelyingPartyIdInvalid); bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), bad_message::AUTH_INVALID_RELYING_PARTY); InvokeCallbackAndCleanup(std::move(callback), @@ -818,6 +850,10 @@ {device::FidoTransportProtocol::kUsbHumanInterfaceDevice}) : transports_; + UMA_HISTOGRAM_COUNTS_100( + "WebAuthentication.CredentialRequestAllowCredentialsCount", + options->allow_credentials.size()); + DCHECK(get_assertion_response_callback_.is_null()); get_assertion_response_callback_ = std::move(callback);
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 98977d2a..12f1bca6 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -227,7 +227,8 @@ WebRuntimeFeatures::EnableFeatureFromString( "BlinkGenPropertyTrees", - base::FeatureList::IsEnabled(blink::features::kBlinkGenPropertyTrees)); + base::FeatureList::IsEnabled(blink::features::kBlinkGenPropertyTrees) || + enable_experimental_web_platform_features); WebRuntimeFeatures::EnablePassiveDocumentEventListeners( base::FeatureList::IsEnabled(features::kPassiveDocumentEventListeners));
diff --git a/content/public/android/java/src/org/chromium/content_public/common/ContentSwitches.java b/content/common/android/java_templates/ContentSwitches.java.tmpl similarity index 83% rename from content/public/android/java/src/org/chromium/content_public/common/ContentSwitches.java rename to content/common/android/java_templates/ContentSwitches.java.tmpl index 9a47ed3..334fad3d 100644 --- a/content/public/android/java/src/org/chromium/content_public/common/ContentSwitches.java +++ b/content/common/android/java_templates/ContentSwitches.java.tmpl
@@ -8,7 +8,7 @@ * Contains all of the command line switches that are specific to the content/ * portion of Chromium on Android. */ -public final class ContentSwitches { +public final class ContentSwitches {{ // Tell Java to use the official command line, loaded from the // official-command-line.xml files. WARNING this is not done // immediately on startup, so early running Java code will not see @@ -27,9 +27,6 @@ // Change the url of the JavaScript that gets injected when accessibility mode is enabled. public static final String ACCESSIBILITY_JAVASCRIPT_URL = "accessibility-js-url"; - // Sets the ISO country code that will be used for phone number detection. - public static final String NETWORK_COUNTRY_ISO = "network-country-iso"; - // How much of the browser controls need to be shown before they will auto show. public static final String TOP_CONTROLS_SHOW_THRESHOLD = "top-controls-show-threshold"; @@ -39,16 +36,9 @@ // Native switch - chrome_switches::kDisablePopupBlocking public static final String DISABLE_POPUP_BLOCKING = "disable-popup-blocking"; - // 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"; - // Native switch kInProcessGPU - public static final String IN_PROCESS_GPU = "in-process-gpu"; - // Native switch kProcessType public static final String SWITCH_PROCESS_TYPE = "type"; @@ -74,6 +64,8 @@ // Native switch value kNetworkSandbox public static final String NETWORK_SANDBOX_TYPE = "network"; +{NATIVE_STRINGS} + // Prevent instantiation. - private ContentSwitches() {} -} + private ContentSwitches() {{}} +}}
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom index 3760989..fb914afb 100644 --- a/content/common/renderer.mojom +++ b/content/common/renderer.mojom
@@ -15,6 +15,7 @@ import "third_party/blink/public/mojom/service_worker/embedded_worker.mojom"; import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom"; import "ui/gfx/geometry/mojo/geometry.mojom"; +import "url/mojom/url.mojom"; struct CreateViewParams { // Renderer-wide preferences. @@ -266,7 +267,9 @@ // Tells the renderer process that it has been locked to a site (i.e., a // scheme plus eTLD+1, such as https://google.com), or to a more specific // origin. - SetIsLockedToSite(); + // TODO(nasko): Remove |lock_url| after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + SetIsLockedToSite(url.mojom.Url lock_url); // Tells the renderer to enable V8's memory saving mode when possible. // This is only used when site-per-process is enabled. If the process
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index f92fcb33..b4217dc 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -93,6 +93,7 @@ ":generate_sandboxed_service_srcjar", ":is_ready_to_pay_service_aidl", ":content_public_android_java_enums_srcjar", + ":content_public_android_java_switches_srcjar", "//content/browser/accessibility:content_browser_accessibility_java_enums_srcjar", "//ui/touch_selection:ui_touch_selection_enums_srcjar", "//ui/touch_selection:ui_touch_handle_orientation_srcjar", @@ -284,7 +285,6 @@ "java/src/org/chromium/content_public/browser/WebContentsObserver.java", "java/src/org/chromium/content_public/browser/WebContentsStatics.java", "java/src/org/chromium/content_public/common/ContentProcessInfo.java", - "java/src/org/chromium/content_public/common/ContentSwitches.java", "java/src/org/chromium/content_public/common/ContentUrlConstants.java", "java/src/org/chromium/content_public/common/Referrer.java", "java/src/org/chromium/content_public/common/ResourceRequestBody.java", @@ -368,6 +368,13 @@ ] } +java_cpp_strings("content_public_android_java_switches_srcjar") { + sources = [ + "//content/public/common/content_switches.cc", + ] + template = "//content/common/android/java_templates/ContentSwitches.java.tmpl" +} + generate_jar_jni("jar_jni") { jni_package = "content" classes = [
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java index 6cc28a1..bf93723 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -520,6 +520,20 @@ } } + /** + * Dumps the stack of the child process with |pid| without crashing it. + * @param pid Process id of the child process. + */ + @CalledByNative + private void dumpProcessStack(int pid) { + assert LauncherThread.runningOnLauncherThread(); + ChildProcessLauncherHelperImpl launcher = getByPid(pid); + if (launcher != null) { + ChildProcessConnection connection = launcher.mLauncher.getConnection(); + connection.dumpProcessStack(); + } + } + // Can be called on a number of threads, including launcher, and binder. private static native void nativeOnChildProcessStarted( long nativeChildProcessLauncherHelper, int pid);
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h index 19063d33..7463db06 100644 --- a/content/public/browser/render_process_host.h +++ b/content/public/browser/render_process_host.h
@@ -276,6 +276,9 @@ #if defined(OS_ANDROID) // Return the highest importance of all widgets in this process. virtual ChildProcessImportance GetEffectiveImportance() = 0; + + // Dumps the stack of this render process without crashing it. + virtual void DumpProcessStack() = 0; #endif // Sets a flag indicating that the process can be abnormally terminated.
diff --git a/content/public/browser/site_instance.h b/content/public/browser/site_instance.h index 3b4c1cf..050707a 100644 --- a/content/public/browser/site_instance.h +++ b/content/public/browser/site_instance.h
@@ -175,6 +175,20 @@ // ContentBrowserClient::GetEffectiveURL(). static GURL GetSiteForURL(BrowserContext* context, const GURL& url); + // Starts requiring a dedicated process for |url|'s site. On platforms where + // strict site isolation is disabled, this may be used as a runtime signal + // that a certain site should become process-isolated, because its security + // is important to the user (e.g., if the user has typed a password on that + // site). The site will be determined from |url|'s scheme and eTLD+1. If + // |context| is non-null, the site will be isolated only within that + // BrowserContext; if |context| is null, the site will be isolated globally + // for all BrowserContexts. + // + // Note that this has no effect if site isolation is turned off, such as via + // the kDisableSiteIsolation cmdline flag or enterprise policy -- see also + // SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled(). + static void StartIsolatingSite(BrowserContext* context, const GURL& url); + protected: friend class base::RefCounted<SiteInstance>;
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc index ba22edf7..0f23b9c 100644 --- a/content/public/browser/site_isolation_policy.cc +++ b/content/public/browser/site_isolation_policy.cc
@@ -116,6 +116,11 @@ } // static +bool SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled() { + return !IsSiteIsolationDisabled(); +} + +// static std::vector<url::Origin> SiteIsolationPolicy::GetIsolatedOriginsFromEnvironment() { std::string cmdline_arg =
diff --git a/content/public/browser/site_isolation_policy.h b/content/public/browser/site_isolation_policy.h index e3348681..d236aa4c 100644 --- a/content/public/browser/site_isolation_policy.h +++ b/content/public/browser/site_isolation_policy.h
@@ -48,6 +48,11 @@ // process iframes (OOPIF's) to print properly. static bool ShouldPdfCompositorBeEnabledForOopifs(); + // Returns true if isolated origins may be added at runtime in response + // to hints such as users typing in a password or (in the future) an origin + // opting itself into isolation via a header. + static bool AreDynamicIsolatedOriginsEnabled(); + // Returns the origins to isolate. See also AreIsolatedOriginsEnabled. // This list applies globally to the whole browser in all profiles. static std::vector<url::Origin> GetIsolatedOrigins();
diff --git a/content/public/browser/tts_controller.h b/content/public/browser/tts_controller.h index 548ede8..82f0ede 100644 --- a/content/public/browser/tts_controller.h +++ b/content/public/browser/tts_controller.h
@@ -97,6 +97,9 @@ // as well. virtual void Stop() = 0; + // Stops the current utterance if it matches the given |source_url|. + virtual void Stop(const GURL& source_url) = 0; + // Pause the speech queue. Some engines may support pausing in the middle // of an utterance. virtual void Pause() = 0;
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc index 0da619e..48b6543 100644 --- a/content/public/test/mock_render_process_host.cc +++ b/content/public/test/mock_render_process_host.cc
@@ -306,6 +306,8 @@ NOTIMPLEMENTED(); return ChildProcessImportance::NORMAL; } + +void MockRenderProcessHost::DumpProcessStack() {} #endif void MockRenderProcessHost::SetSuddenTerminationAllowed(bool allowed) {
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h index a963922..b6d205c 100644 --- a/content/public/test/mock_render_process_host.h +++ b/content/public/test/mock_render_process_host.h
@@ -110,6 +110,7 @@ void RemovePriorityClient(PriorityClient* priority_client) override; #if defined(OS_ANDROID) ChildProcessImportance GetEffectiveImportance() override; + void DumpProcessStack() override; #endif void SetSuddenTerminationAllowed(bool allowed) override; bool SuddenTerminationAllowed() override;
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc index 590c97d..863149f 100644 --- a/content/renderer/input/widget_input_handler_manager.cc +++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -403,9 +403,17 @@ WidgetInputHandlerManager* manager = render_widget->widget_input_handler_manager(); + // TODO(bokan): The synchronous compositor doesn't support the + // RequestPresentation API yet so just ACK the gesture immediately so it + // doesn't hang forever. https://crbug.com/938956. + bool sync_compositing = false; +#if defined(OS_ANDROID) + sync_compositing = GetContentClient()->UsingSynchronousCompositing(); +#endif + // If the RenderWidget is hidden, we won't produce compositor frames for it // so just ACK the input to prevent blocking the browser indefinitely. - if (render_widget->is_hidden()) { + if (render_widget->is_hidden() || sync_compositing) { manager->InvokeInputProcessedCallback(); return; }
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc index 43c31144..a655afb54 100644 --- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc +++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -209,8 +209,7 @@ std::unique_ptr<media::VideoDecoder> GpuVideoAcceleratorFactoriesImpl::CreateVideoDecoder( media::MediaLog* media_log, - const media::RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) { + const media::RequestOverlayInfoCB& request_overlay_info_cb) { DCHECK(video_accelerator_enabled_); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(interface_factory_.is_bound()); @@ -223,12 +222,12 @@ interface_factory_->CreateVideoDecoder(mojo::MakeRequest(&video_decoder)); return std::make_unique<media::MojoVideoDecoder>( task_runner_, this, media_log, std::move(video_decoder), - request_overlay_info_cb, target_color_space); + request_overlay_info_cb, rendering_color_space_); } #endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER) return std::make_unique<media::GpuVideoDecoder>( - this, request_overlay_info_cb, target_color_space, media_log); + this, request_overlay_info_cb, rendering_color_space_, media_log); } std::unique_ptr<media::VideoDecodeAccelerator>
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h index faa69c6..08a215bd 100644 --- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h +++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
@@ -71,8 +71,7 @@ int32_t GetCommandBufferRouteId() override; std::unique_ptr<media::VideoDecoder> CreateVideoDecoder( media::MediaLog* media_log, - const media::RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) override; + const media::RequestOverlayInfoCB& request_overlay_info_cb) override; bool IsDecoderConfigSupported( const media::VideoDecoderConfig& config) override; std::unique_ptr<media::VideoDecodeAccelerator> CreateVideoDecodeAccelerator()
diff --git a/content/renderer/media/media_interface_factory.cc b/content/renderer/media/media_interface_factory.cc index 4797c54..54695766 100644 --- a/content/renderer/media/media_interface_factory.cc +++ b/content/renderer/media/media_interface_factory.cc
@@ -51,15 +51,6 @@ GetMediaInterfaceFactory()->CreateVideoDecoder(std::move(request)); } -// TODO(https://crbug.com/936528) : remove this method. -void MediaInterfaceFactory::CreateRenderer( - media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) { - DCHECK_EQ(type, media::mojom::HostedRendererType::kDefault); - CreateDefaultRenderer(audio_device_id, std::move(renderer)); -} - void MediaInterfaceFactory::CreateDefaultRenderer( const std::string& audio_device_id, media::mojom::RendererRequest request) {
diff --git a/content/renderer/media/media_interface_factory.h b/content/renderer/media/media_interface_factory.h index aa05860..67b2d19 100644 --- a/content/renderer/media/media_interface_factory.h +++ b/content/renderer/media/media_interface_factory.h
@@ -35,10 +35,6 @@ void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final; void CreateDefaultRenderer(const std::string& audio_device_id, media::mojom::RendererRequest request) final; - // TODO(https://crbug.com/936528) : remove this method. - void CreateRenderer(media::mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) final; #if defined(OS_ANDROID) void CreateFlingingRenderer(const std::string& presentation_id, media::mojom::RendererRequest request) final;
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc index 6b51dd2..9c4d2799 100644 --- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc +++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <functional> +#include <utility> #include "base/bind.h" #include "base/bind_helpers.h" @@ -22,10 +23,10 @@ #include "build/build_config.h" #include "content/renderer/media/render_media_log.h" #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" +#include "content/renderer/media/webrtc/webrtc_video_utils.h" #include "media/base/media_log.h" #include "media/base/media_util.h" #include "media/base/overlay_info.h" -#include "media/base/video_decoder_config.h" #include "media/base/video_types.h" #include "media/video/gpu_video_accelerator_factories.h" #include "third_party/webrtc/api/video/video_frame.h" @@ -159,7 +160,8 @@ // Synchronously verify that the decoder can be initialized. std::unique_ptr<RTCVideoDecoderAdapter> rtc_video_decoder_adapter = - base::WrapUnique(new RTCVideoDecoderAdapter(gpu_factories, format)); + base::WrapUnique( + new RTCVideoDecoderAdapter(gpu_factories, config, format)); if (!rtc_video_decoder_adapter->InitializeSync(config)) { gpu_factories->GetTaskRunner()->DeleteSoon( FROM_HERE, std::move(rtc_video_decoder_adapter)); @@ -171,10 +173,12 @@ RTCVideoDecoderAdapter::RTCVideoDecoderAdapter( media::GpuVideoAcceleratorFactories* gpu_factories, + const media::VideoDecoderConfig& config, const webrtc::SdpVideoFormat& format) : media_task_runner_(gpu_factories->GetTaskRunner()), gpu_factories_(gpu_factories), format_(format), + config_(config), weak_this_factory_(this) { DVLOG(1) << __func__; DETACH_FROM_THREAD(decoding_thread_checker_); @@ -189,7 +193,8 @@ bool RTCVideoDecoderAdapter::InitializeSync( const media::VideoDecoderConfig& config) { DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); + // Can be called on |worker_thread_| or |decoding_thread_|. + DCHECK(!media_task_runner_->BelongsToCurrentThread()); bool result = false; base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::MANUAL, @@ -249,6 +254,15 @@ buffer->set_timestamp( base::TimeDelta::FromMicroseconds(input_image.Timestamp())); + if (ShouldReinitializeForSettingHDRColorSpace(input_image)) { + config_.set_color_space_info( + WebRtcToMediaVideoColorSpace(*input_image.ColorSpace())); + if (!ReinitializeSync(config_)) + return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; + if (input_image._frameType != webrtc::kVideoFrameKey) + return WEBRTC_VIDEO_CODEC_ERROR; + } + // Queue for decoding. { base::AutoLock auto_lock(lock_); @@ -306,17 +320,20 @@ DVLOG(3) << __func__; DCHECK(media_task_runner_->BelongsToCurrentThread()); - // TODO(sandersd): Plumb a real log sink here so that we can contribute to the - // media-internals UI. The current log just discards all messages. - media_log_ = std::make_unique<media::NullMediaLog>(); - - video_decoder_ = gpu_factories_->CreateVideoDecoder( - media_log_.get(), base::BindRepeating(&OnRequestOverlayInfo), - gfx::ColorSpace()); + // On ReinitializeSync() calls, |video_decoder_| may already be set. if (!video_decoder_) { - media_task_runner_->PostTask(FROM_HERE, - base::BindRepeating(init_cb, false)); - return; + // TODO(sandersd): Plumb a real log sink here so that we can contribute to + // the media-internals UI. The current log just discards all messages. + media_log_ = std::make_unique<media::NullMediaLog>(); + + video_decoder_ = gpu_factories_->CreateVideoDecoder( + media_log_.get(), base::BindRepeating(&OnRequestOverlayInfo)); + + if (!video_decoder_) { + media_task_runner_->PostTask(FROM_HERE, + base::BindRepeating(init_cb, false)); + return; + } } // In practice this is ignored by hardware decoders. @@ -407,4 +424,67 @@ consecutive_error_count_ = 0; } +bool RTCVideoDecoderAdapter::ShouldReinitializeForSettingHDRColorSpace( + const webrtc::EncodedImage& input_image) const { + DCHECK_CALLED_ON_VALID_THREAD(decoding_thread_checker_); + + if (config_.profile() == media::VP9PROFILE_PROFILE2 && + input_image.ColorSpace()) { + const media::VideoColorSpace& new_color_space = + WebRtcToMediaVideoColorSpace(*input_image.ColorSpace()); + if (!config_.color_space_info().IsSpecified() || + new_color_space != config_.color_space_info()) { + return true; + } + } + return false; +} + +bool RTCVideoDecoderAdapter::ReinitializeSync( + const media::VideoDecoderConfig& config) { + DCHECK_CALLED_ON_VALID_THREAD(decoding_thread_checker_); + + bool result = false; + base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + media::VideoDecoder::InitCB init_cb = + base::BindRepeating(&FinishWait, &waiter, &result); + FlushDoneCB flush_success_cb = + base::BindOnce(&RTCVideoDecoderAdapter::InitializeOnMediaThread, + weak_this_, std::cref(config), std::cref(init_cb)); + FlushDoneCB flush_fail_cb = + base::BindOnce(&FinishWait, &waiter, &result, false); + if (media_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&RTCVideoDecoderAdapter::FlushOnMediaThread, + weak_this_, std::move(flush_success_cb), + std::move(flush_fail_cb)))) { + waiter.Wait(); + } + return result; +} + +void RTCVideoDecoderAdapter::FlushOnMediaThread(FlushDoneCB flush_success_cb, + FlushDoneCB flush_fail_cb) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + // Remove any pending tasks. + { + base::AutoLock auto_lock(lock_); + pending_buffers_.clear(); + } + + // Send EOS frame for flush. + video_decoder_->Decode( + media::DecoderBuffer::CreateEOSBuffer(), + base::BindRepeating( + [](FlushDoneCB flush_success, FlushDoneCB flush_fail, + media::DecodeStatus status) { + if (status == media::DecodeStatus::OK) + std::move(flush_success).Run(); + else + std::move(flush_fail).Run(); + }, + base::Passed(&flush_success_cb), base::Passed(&flush_fail_cb))); +} + } // namespace content
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.h b/content/renderer/media/webrtc/rtc_video_decoder_adapter.h index 048962ad..f4d3d3ce 100644 --- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.h +++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.h
@@ -18,6 +18,7 @@ #include "media/base/decode_status.h" #include "media/base/video_codecs.h" #include "media/base/video_decoder.h" +#include "media/base/video_decoder_config.h" #include "third_party/webrtc/api/video_codecs/sdp_video_format.h" #include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h" #include "ui/gfx/geometry/size.h" @@ -30,7 +31,6 @@ class DecoderBuffer; class GpuVideoAcceleratorFactories; class MediaLog; -class VideoDecoderConfig; class VideoFrame; } // namespace media @@ -81,9 +81,11 @@ using CreateVideoDecoderCB = base::RepeatingCallback<std::unique_ptr<media::VideoDecoder>( media::MediaLog*)>; + using FlushDoneCB = base::OnceCallback<void()>; // Called on the worker thread. RTCVideoDecoderAdapter(media::GpuVideoAcceleratorFactories* gpu_factories, + const media::VideoDecoderConfig& config, const webrtc::SdpVideoFormat& format); bool InitializeSync(const media::VideoDecoderConfig& config); @@ -93,10 +95,17 @@ void OnDecodeDone(media::DecodeStatus status); void OnOutput(const scoped_refptr<media::VideoFrame>& frame); + bool ShouldReinitializeForSettingHDRColorSpace( + const webrtc::EncodedImage& input_image) const; + bool ReinitializeSync(const media::VideoDecoderConfig& config); + void FlushOnMediaThread(FlushDoneCB flush_success_cb, + FlushDoneCB flush_fail_cb); + // Construction parameters. scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; media::GpuVideoAcceleratorFactories* gpu_factories_; webrtc::SdpVideoFormat format_; + media::VideoDecoderConfig config_; // Media thread members. // |media_log_| must outlive |video_decoder_| because it is passed as a raw
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc index 49b09c8..5332faa4 100644 --- a/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc +++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <memory> +#include <utility> #include <vector> #include <stdint.h> @@ -30,6 +31,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/api/video_codecs/video_codec.h" +#include "third_party/webrtc/media/base/vp9_profile.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -91,6 +93,8 @@ RTCVideoDecoderAdapterTest() : media_thread_("Media Thread"), gpu_factories_(nullptr), + sdp_format_(webrtc::SdpVideoFormat( + webrtc::CodecTypeToPayloadString(webrtc::kVideoCodecVP9))), decoded_image_callback_(decoded_cb_.Get()) { media_thread_.Start(); @@ -105,15 +109,14 @@ .WillByDefault(Return(true)); EXPECT_CALL(gpu_factories_, IsDecoderConfigSupported(_)).Times(AtLeast(0)); - ON_CALL(gpu_factories_, CreateVideoDecoder(_, _, _)) + ON_CALL(gpu_factories_, CreateVideoDecoder(_, _)) .WillByDefault( [this](media::MediaLog* media_log, - const media::RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) { + const media::RequestOverlayInfoCB& request_overlay_info_cb) { DCHECK(this->owned_video_decoder_); return std::move(this->owned_video_decoder_); }); - EXPECT_CALL(gpu_factories_, CreateVideoDecoder(_, _, _)).Times(AtLeast(0)); + EXPECT_CALL(gpu_factories_, CreateVideoDecoder(_, _)).Times(AtLeast(0)); } ~RTCVideoDecoderAdapterTest() { @@ -144,12 +147,10 @@ bool CreateAndInitialize(bool init_cb_result = true) { EXPECT_CALL(*video_decoder_, Initialize(_, _, _, _, _, _)) - .WillOnce(DoAll(SaveArg<4>(&output_cb_), + .WillOnce(DoAll(SaveArg<0>(&vda_config_), SaveArg<4>(&output_cb_), media::RunCallback<3>(init_cb_result))); - rtc_video_decoder_adapter_ = RTCVideoDecoderAdapter::Create( - &gpu_factories_, - webrtc::SdpVideoFormat( - webrtc::CodecTypeToPayloadString(webrtc::kVideoCodecVP9))); + rtc_video_decoder_adapter_ = + RTCVideoDecoderAdapter::Create(&gpu_factories_, sdp_format_); return !!rtc_video_decoder_adapter_; } @@ -194,6 +195,25 @@ int32_t Release() { return rtc_video_decoder_adapter_->Release(); } + webrtc::EncodedImage GetEncodedImageWithColorSpace(uint8_t* buf, + uint32_t timestamp) { + webrtc::EncodedImage input_image(buf, 1, 1); + input_image._completeFrame = true; + input_image._frameType = webrtc::kVideoFrameKey; + input_image.SetTimestamp(timestamp); + webrtc::ColorSpace webrtc_color_space; + webrtc_color_space.set_primaries_from_uint8(1); + webrtc_color_space.set_transfer_from_uint8(1); + webrtc_color_space.set_matrix_from_uint8(1); + webrtc_color_space.set_range_from_uint8(1); + input_image.SetColorSpace(webrtc_color_space); + return input_image; + } + + void SetSdpFormat(const webrtc::SdpVideoFormat& sdp_format) { + sdp_format_ = sdp_format; + } + base::test::ScopedTaskEnvironment scoped_task_environment_; base::Thread media_thread_; @@ -205,9 +225,11 @@ decoded_cb_; StrictMock<media::MockGpuVideoAcceleratorFactories> gpu_factories_; + media::VideoDecoderConfig vda_config_; std::unique_ptr<RTCVideoDecoderAdapter> rtc_video_decoder_adapter_; private: + webrtc::SdpVideoFormat sdp_format_; std::unique_ptr<StrictMock<MockVideoDecoder>> owned_video_decoder_; DecodedImageCallback decoded_image_callback_; media::VideoDecoder::OutputCB output_cb_; @@ -301,4 +323,80 @@ FAIL(); } +TEST_F(RTCVideoDecoderAdapterTest, ReinitializesForHDRColorSpaceInitially) { + SetSdpFormat(webrtc::SdpVideoFormat( + "VP9", {{webrtc::kVP9FmtpProfileId, + webrtc::VP9ProfileToString(webrtc::VP9Profile::kProfile2)}})); + ASSERT_TRUE(BasicSetup()); + EXPECT_EQ(media::VP9PROFILE_PROFILE2, vda_config_.profile()); + EXPECT_FALSE(vda_config_.color_space_info().IsSpecified()); + uint8_t buf[] = {0}; + + // Decode() is expected to be called for EOS flush as well. + EXPECT_CALL(*video_decoder_, Decode(_, _)) + .Times(3) + .WillRepeatedly(media::RunCallback<1>(media::DecodeStatus::OK)); + EXPECT_CALL(decoded_cb_, Run(_)).Times(2); + + // First Decode() should cause a reinitialize as new color space is given. + EXPECT_CALL(*video_decoder_, Initialize(_, _, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&vda_config_), media::RunCallback<3>(true))); + webrtc::EncodedImage first_input_image = + GetEncodedImageWithColorSpace(&buf[0], 0); + ASSERT_EQ( + rtc_video_decoder_adapter_->Decode(first_input_image, false, nullptr, 0), + WEBRTC_VIDEO_CODEC_OK); + media_thread_.FlushForTesting(); + EXPECT_TRUE(vda_config_.color_space_info().IsSpecified()); + FinishDecode(0); + media_thread_.FlushForTesting(); + + // Second Decode() with same params should happen normally. + webrtc::EncodedImage second_input_image = + GetEncodedImageWithColorSpace(&buf[0], 1); + ASSERT_EQ( + rtc_video_decoder_adapter_->Decode(second_input_image, false, nullptr, 0), + WEBRTC_VIDEO_CODEC_OK); + FinishDecode(1); + media_thread_.FlushForTesting(); +} + +TEST_F(RTCVideoDecoderAdapterTest, HandlesReinitializeFailure) { + SetSdpFormat(webrtc::SdpVideoFormat( + "VP9", {{webrtc::kVP9FmtpProfileId, + webrtc::VP9ProfileToString(webrtc::VP9Profile::kProfile2)}})); + ASSERT_TRUE(BasicSetup()); + EXPECT_EQ(media::VP9PROFILE_PROFILE2, vda_config_.profile()); + EXPECT_FALSE(vda_config_.color_space_info().IsSpecified()); + uint8_t buf[] = {0}; + webrtc::EncodedImage input_image = GetEncodedImageWithColorSpace(&buf[0], 0); + + // Decode() is expected to be called for EOS flush as well. + EXPECT_CALL(*video_decoder_, Decode(_, _)) + .WillOnce(media::RunCallback<1>(media::DecodeStatus::OK)); + + // Set Initialize() to fail. + EXPECT_CALL(*video_decoder_, Initialize(_, _, _, _, _, _)) + .WillOnce(media::RunCallback<3>(false)); + ASSERT_EQ(rtc_video_decoder_adapter_->Decode(input_image, false, nullptr, 0), + WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); +} + +TEST_F(RTCVideoDecoderAdapterTest, HandlesFlushFailure) { + SetSdpFormat(webrtc::SdpVideoFormat( + "VP9", {{webrtc::kVP9FmtpProfileId, + webrtc::VP9ProfileToString(webrtc::VP9Profile::kProfile2)}})); + ASSERT_TRUE(BasicSetup()); + EXPECT_EQ(media::VP9PROFILE_PROFILE2, vda_config_.profile()); + EXPECT_FALSE(vda_config_.color_space_info().IsSpecified()); + uint8_t buf[] = {0}; + webrtc::EncodedImage input_image = GetEncodedImageWithColorSpace(&buf[0], 0); + + // Decode() is expected to be called for EOS flush, set to fail. + EXPECT_CALL(*video_decoder_, Decode(_, _)) + .WillOnce(media::RunCallback<1>(media::DecodeStatus::ABORTED)); + ASSERT_EQ(rtc_video_decoder_adapter_->Decode(input_image, false, nullptr, 0), + WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); +} + } // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 1c4ae023..b82743e 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2863,7 +2863,8 @@ frame_->EnableViewSourceMode(false); auto navigation_params = WebNavigationParams::CreateForErrorPage( - document_loader, error_html, GURL(kUnreachableWebDataURL), error.url()); + document_loader, error_html, GURL(kUnreachableWebDataURL), error.url(), + error.reason()); std::unique_ptr<DocumentState> document_state; if (inherit_document_state) { @@ -3600,6 +3601,7 @@ FillNavigationParamsRequest(common_params, commit_params, navigation_params.get()); navigation_params->url = GURL(kUnreachableWebDataURL); + navigation_params->error_code = error_code; if (!ShouldDisplayErrorPageForFailedLoad(error_code, common_params.url)) { // The browser expects this frame to be loading an error page. Inform it @@ -6022,15 +6024,51 @@ DCHECK(!(was_within_same_document && interface_params)); UpdateStateForCommit(item, commit_type, transition); + auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition); + + // If this is a regular commit, not an error page, the URL that was just + // committed must match the process lock, if there is one. Verify it here, to + // get a stack trace for a bug where this seems to be occurring. + // TODO(nasko): Remove this check after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + RenderThreadImpl* render_thread = RenderThreadImpl::current(); + const GURL* lock_url = + render_thread ? render_thread->site_lock_url() : nullptr; + if (frame_->GetDocumentLoader()->ErrorCode() != net::ERR_BLOCKED_BY_CLIENT && + lock_url && lock_url->scheme() == params->url.scheme() && + lock_url->SchemeIsHTTPOrHTTPS()) { + std::string lock_domain = + net::registry_controlled_domains::GetDomainAndRegistry( + lock_url->host(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + std::string commit_domain = + net::registry_controlled_domains::GetDomainAndRegistry( + params->url.host(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + if (lock_domain != commit_domain) { + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString( + "lock_domain", base::debug::CrashKeySize::Size64), + lock_domain); + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString( + "commit_domain", base::debug::CrashKeySize::Size64), + commit_domain); + base::debug::SetCrashKeyString( + base::debug::AllocateCrashKeyString( + "is_subframe", base::debug::CrashKeySize::Size32), + is_main_frame_ ? "true" : "false"); + CHECK(false); + } + } + // This invocation must precede any calls to allowScripts(), allowImages(), or // allowPlugins() for the new page. This ensures that when these functions // send ViewHostMsg_ContentBlocked messages, those arrive after the browser // process has already been informed of the provisional load committing. if (was_within_same_document) { - GetFrameHost()->DidCommitSameDocumentNavigation( - MakeDidCommitProvisionalLoadParams(commit_type, transition)); + GetFrameHost()->DidCommitSameDocumentNavigation(std::move(params)); } else { - auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition); NavigationState* navigation_state = NavigationState::FromDocumentLoader(frame_->GetDocumentLoader()); if (navigation_state->uses_per_navigation_mojo_interface()) {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 44d96379..9d029d4 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -1711,9 +1711,10 @@ base::TimeDelta::FromMinutes(90)); } -void RenderThreadImpl::SetIsLockedToSite() { +void RenderThreadImpl::SetIsLockedToSite(const GURL& lock_url) { DCHECK(blink_platform_impl_); blink_platform_impl_->SetIsLockedToSite(); + site_lock_url_ = std::make_unique<GURL>(lock_url); } void RenderThreadImpl::EnableV8LowMemoryMode() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index afa96183..11d7639 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -494,6 +494,10 @@ video_frame_compositor_task_runner_ = task_runner; } + // TODO(nasko): Remove after we've gathered enough information to debug issues + // with browser-side security checks. https://crbug.com/931895. + const GURL* site_lock_url() { return site_lock_url_.get(); } + private: friend class RenderThreadImplBrowserTest; @@ -551,7 +555,7 @@ void SetProcessState(mojom::RenderProcessState process_state) override; void SetSchedulerKeepActive(bool keep_active) override; void ProcessPurgeAndSuspend() override; - void SetIsLockedToSite() override; + void SetIsLockedToSite(const GURL& lock_url) override; void EnableV8LowMemoryMode() override; void OnMemoryPressure( @@ -752,6 +756,11 @@ mojo::Binding<viz::mojom::CompositingModeWatcher> compositing_mode_watcher_binding_; + // TODO(nasko): Temporary diagnostic member, holding the site URL this process + // is locked to. Remove after we've gathered enough information to + // debug issues with browser-side security checks. https://crbug.com/931895. + std::unique_ptr<GURL> site_lock_url_; + base::WeakPtrFactory<RenderThreadImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index 0c503a61..0e48435 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -517,6 +517,11 @@ v8::Local<v8::Context> context) { CHECK(worker_task_runner_->RunsTasksInCurrentSequence()); RecordDebugLog("WillDestroyWorkerContext"); + if (dispatching_fetch_event_) { + CrashWithDebugLog("WDWC_DFE"); + return; + } + // At this point WillStopCurrentWorkerThread is already called, so // worker_task_runner_->RunsTasksInCurrentSequence() returns false // (while we're still on the worker thread). @@ -1481,9 +1486,10 @@ DispatchFetchEventCallback callback) { CHECK(worker_task_runner_->RunsTasksInCurrentSequence()); if (!context_) { - CrashWithDebugLog("DFE"); + CrashWithDebugLog("DFE1"); return; } + dispatching_fetch_event_ = true; int event_id = context_->timeout_timer->StartEvent( CreateAbortCallback(&context_->fetch_event_callbacks)); context_->fetch_event_callbacks.emplace(event_id, std::move(callback)); @@ -1509,7 +1515,12 @@ blink::WebServiceWorkerRequest web_request; ToWebServiceWorkerRequestForFetchEvent(std::move(params->request), params->client_id, &web_request); + if (!context_) { + CrashWithDebugLog("DFE2"); + return; + } proxy_->DispatchFetchEvent(event_id, web_request, navigation_preload_sent); + dispatching_fetch_event_ = false; } void ServiceWorkerContextClient::DispatchNotificationClickEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h index be31fe2..175b509 100644 --- a/content/renderer/service_worker/service_worker_context_client.h +++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -435,6 +435,7 @@ bool report_debug_log_ = true; base::Lock debug_log_lock_; std::deque<std::string> debug_log_ GUARDED_BY(debug_log_lock_); + bool dispatching_fetch_event_ = false; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextClient); };
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc index dec7a84..0cdced7 100644 --- a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc +++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
@@ -19,21 +19,6 @@ namespace content { -namespace { -// Returns whether it's possible for a document whose frame is a descendant of -// |frame| to be a secure context, not considering scheme exceptions (since any -// document can be a secure context if it has a scheme exception). See -// Document::isSecureContextImpl for more details. -bool IsFrameSecure(blink::WebFrame* frame) { - while (frame) { - if (!frame->GetSecurityOrigin().IsPotentiallyTrustworthy()) - return false; - frame = frame->Parent(); - } - return true; -} -} // namespace - class ServiceWorkerNetworkProviderForFrame::NewDocumentObserver : public RenderFrameObserver { public: @@ -78,21 +63,13 @@ scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory) { DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)); - // Ideally Document::IsSecureContext would be called here, but the document is - // not created yet, and due to redirects the URL may change. So pass - // is_parent_frame_secure to the browser process, so it can determine the - // context security when deciding whether to allow a service worker to control - // the document. - const bool is_parent_frame_secure = - IsFrameSecure(frame->GetWebFrame()->Parent()); - auto provider = base::WrapUnique(new ServiceWorkerNetworkProviderForFrame(frame)); auto host_info = blink::mojom::ServiceWorkerProviderHostInfo::New( provider_id, frame->GetRoutingID(), blink::mojom::ServiceWorkerProviderType::kForWindow, - is_parent_frame_secure, nullptr /* host_request */, + false /* is_parent_frame_secure */, nullptr /* host_request */, nullptr /* client_ptr_info */); blink::mojom::ServiceWorkerContainerAssociatedRequest client_request = mojo::MakeRequest(&host_info->client_ptr_info);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 33a601f8..523d1cb3 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1139,6 +1139,7 @@ sources += [ "../browser/accessibility/accessibility_win_browsertest.cc", "../browser/accessibility/ax_platform_node_win_browsertest.cc", + "../browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc", "../browser/renderer_host/direct_manipulation_browsertest.cc", ] @@ -1560,6 +1561,7 @@ "../browser/notifications/notification_event_dispatcher_impl_unittest.cc", "../browser/notifications/notification_id_generator_unittest.cc", "../browser/notifications/notification_storage_unittest.cc", + "../browser/notifications/platform_notification_context_trigger_unittest.cc", "../browser/notifications/platform_notification_context_unittest.cc", "../browser/payments/payment_app_content_unittest_base.cc", "../browser/payments/payment_app_content_unittest_base.h",
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index 4b1ad04..0c8f85b 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -152,3 +152,7 @@ bug=927901) self.Skip('Pixel_Video_VP9_DXVA', ['linux', 'android', 'mac', 'chromeos'], bug=927901) + + # Complex overlays test is flaky on Nvidia probably due to its small size. + self.Flaky('Pixel_DirectComposition_ComplexOverlays', ['win', 'nvidia'], + bug=929425)
diff --git a/content/test/gpu/gpu_tests/trace_test_expectations.py b/content/test/gpu/gpu_tests/trace_test_expectations.py index 559f5a3..de36ffb 100644 --- a/content/test/gpu/gpu_tests/trace_test_expectations.py +++ b/content/test/gpu/gpu_tests/trace_test_expectations.py
@@ -31,3 +31,7 @@ self.Fail('VideoPathTraceTest_DirectComposition_Video_VP9_Fullsize', ['win', 'intel'], bug=930343) + # Complex overlays test is flaky on Nvidia probably due to its small size. + self.Flaky('VideoPathTraceTest_DirectComposition_ComplexOverlays', + ['win', 'nvidia'], bug=937545) +
diff --git a/device/usb/public/mojom/BUILD.gn b/device/usb/public/mojom/BUILD.gn index 23a8a97..1de3791 100644 --- a/device/usb/public/mojom/BUILD.gn +++ b/device/usb/public/mojom/BUILD.gn
@@ -34,6 +34,7 @@ "//components/arc/common:common_blink", "//third_party/blink/public/mojom/usb:usb_blink", "//third_party/blink/renderer/modules/webusb", + "//chrome/browser/ui/webui/usb_internals:mojo_bindings_blink", ] }
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc index daf2c813..8c1b2a4b 100644 --- a/device/vr/android/gvr/gvr_device.cc +++ b/device/vr/android/gvr/gvr_device.cc
@@ -227,18 +227,6 @@ exclusive_controller_binding_.Close(); } -void GvrDevice::OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) { - if (!gvr_api_) { - std::move(callback).Run(nullptr); - return; - } - mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); - frame_data->pose = - GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), nullptr); - std::move(callback).Run(std::move(frame_data)); -} - void GvrDevice::OnListeningForActivate(bool listening) { GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider(); if (!delegate_provider) @@ -365,13 +353,7 @@ return; } - if (!options->immersive) { - // TODO(https://crbug.com/695937): This should be NOTREACHED() once we no - // longer need the hacked GVR non-immersive mode. This should now only be - // hit if orientation devices are disabled by flag. - ReturnNonImmersiveSession(std::move(pending_request_session_callback_)); - return; - } + DCHECK(options->immersive); // StartWebXRPresentation is async as we may trigger a DON (Device ON) flow // that pauses Chrome.
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h index da05cef..875a272 100644 --- a/device/vr/android/gvr/gvr_device.h +++ b/device/vr/android/gvr/gvr_device.h
@@ -45,8 +45,6 @@ private: // VRDeviceBase void OnListeningForActivate(bool listening) override; - void OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) override; void OnStartPresentResult(mojom::XRSessionPtr session);
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc index 8a37118..495af89 100644 --- a/device/vr/oculus/oculus_device.cc +++ b/device/vr/oculus/oculus_device.cc
@@ -133,10 +133,7 @@ return; } - if (!options->immersive) { - ReturnNonImmersiveSession(std::move(callback)); - return; - } + DCHECK(options->immersive); StopOvrSession(); @@ -285,20 +282,6 @@ } } -void OculusDevice::OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) { - if (!session_) { - std::move(callback).Run(nullptr); - return; - } - - ovrTrackingState state = ovr_GetTrackingState(session_, 0, false); - - mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); - frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose); - std::move(callback).Run(std::move(frame_data)); -} - void OculusDevice::GetIsolatedXRGamepadProvider( mojom::IsolatedXRGamepadProviderRequest provider_request) { // We bind the provider_request on the render loop thread, so gamepad data is
diff --git a/device/vr/oculus/oculus_device.h b/device/vr/oculus/oculus_device.h index a825d2d1..5134c3bf 100644 --- a/device/vr/oculus/oculus_device.h +++ b/device/vr/oculus/oculus_device.h
@@ -37,8 +37,6 @@ void EnsureInitialized(int render_process_id, int render_frame_id, EnsureInitializedCallback callback) override; - void OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) override; void OnRequestSessionResult(mojom::XRRuntime::RequestSessionCallback callback, bool result, mojom::XRSessionPtr session);
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc index 7d2bdb8..a1b02aee 100644 --- a/device/vr/openvr/openvr_device.cc +++ b/device/vr/openvr/openvr_device.cc
@@ -181,10 +181,7 @@ return; } - if (!options->immersive) { - ReturnNonImmersiveSession(std::move(callback)); - return; - } + DCHECK(options->immersive); if (!render_loop_->IsRunning()) { render_loop_->Start(); @@ -334,23 +331,6 @@ exclusive_controller_binding_.Close(); } -void OpenVRDevice::OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) { - if (!openvr_) { - std::move(callback).Run(nullptr); - return; - } - const float kPredictionTimeSeconds = 0.03f; - vr::TrackedDevicePose_t rendering_poses[vr::k_unMaxTrackedDeviceCount]; - openvr_->GetSystem()->GetDeviceToAbsoluteTrackingPose( - vr::TrackingUniverseSeated, kPredictionTimeSeconds, rendering_poses, - vr::k_unMaxTrackedDeviceCount); - mojom::XRFrameDataPtr data = mojom::XRFrameData::New(); - data->pose = mojo::ConvertTo<mojom::VRPosePtr>( - rendering_poses[vr::k_unTrackedDeviceIndex_Hmd]); - std::move(callback).Run(std::move(data)); -} - // Only deal with events that will cause displayInfo changes for now. void OpenVRDevice::OnPollingEvents() { main_thread_task_runner_->PostDelayedTask(
diff --git a/device/vr/openvr/openvr_device.h b/device/vr/openvr/openvr_device.h index cbec7eb..fed1fca8 100644 --- a/device/vr/openvr/openvr_device.h +++ b/device/vr/openvr/openvr_device.h
@@ -52,10 +52,6 @@ mojom::XRCompositorHostPtr BindCompositorHost(); private: - // VRDeviceBase - void OnGetInlineFrameData( - mojom::XRFrameDataProvider::GetFrameDataCallback callback) override; - // XRSessionController void SetFrameDataRestricted(bool restricted) override;
diff --git a/device/vr/windows_mixed_reality/mixed_reality_device.cc b/device/vr/windows_mixed_reality/mixed_reality_device.cc index 7f8c7d0..cd792a7 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_device.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_device.cc
@@ -88,10 +88,7 @@ void MixedRealityDevice::RequestSession( mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) { - if (!options->immersive) { - ReturnNonImmersiveSession(std::move(callback)); - return; - } + DCHECK(options->immersive); if (!render_loop_) CreateRenderLoop();
diff --git a/docs/android_accessing_cpp_switches_in_java.md b/docs/android_accessing_cpp_switches_in_java.md new file mode 100644 index 0000000..b9f12f2 --- /dev/null +++ b/docs/android_accessing_cpp_switches_in_java.md
@@ -0,0 +1,93 @@ +# Accessing C++ Switches In Java + +[TOC] + +## Introduction + +Accessing C++ switches in Java is implemented via a Python script which analyzes +the C++ switches file and spits out the corresponding Java class. The generated +class name will be based upon the switch file name, and the path must be +specified in a comment within the switch file itself. + +## Usage + +1. Add directives to your C++ switch file + + ```cpp + // GENERATED_JAVA_PACKAGE: org.chromium.chrome + + // ...snip... + + // Documentation for the following switch. + const char kSomeSwitch[] = "some-switch"; + + // ...snip... + ``` + +2. Create a template file + ```java + // Copyright {YEAR} 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. + + // This file is autogenerated by + // {SCRIPT_NAME} + // From + // {SOURCE_PATH}, and + // {TEMPLATE_PATH} + + package my.java.package + + // Be sure to escape any curly braces in your template by doubling as + // follows. + public abstract class MySwitches {{ + + {NATIVE_SWITCHES} + + }} + ``` + +3. Add a new build target + + ```gn + import("//build/config/android/rules.gni") + + java_cpp_strings("foo_generated_switch") { + sources = [ + "//base/android/native_foo_switches.cc", + ] + template = "//base/android/java_templates/MySwitches.java.tmpl" + } + ``` + +5. Add the new target to the desired android_library targets srcjar_deps: + + ```gn + android_library("base_java") { + srcjar_deps = [ + ":foo_generated_switches", + ] + } + ``` + +5. The generated file `org/chromium/chrome/NativeFooSwitches.java` would contain: + + ```java + package org.chromium.chrome; + + public final class NativeFooSwitches { + // ...snip... + + public static final String SOME_SWITCH = "some-switch"; + + // ...snip... + } + ``` + +## Code +* [Generator +code](https://cs.chromium.org/chromium/src/build/android/gyp/java_cpp_strings.py?dr=C&sq=package:chromium) +and +[Tests](https://cs.chromium.org/chromium/src/build/android/gyp/java_cpp_strings_tests.py?dr=C&sq=package:chromium) +* [GN +template](https://cs.chromium.org/chromium/src/build/config/android/rules.gni?sq=package:chromium&dr=C)
diff --git a/docs/memory/debugging_memory_issues.md b/docs/memory/debugging_memory_issues.md index 83cab2e..f7738a72 100644 --- a/docs/memory/debugging_memory_issues.md +++ b/docs/memory/debugging_memory_issues.md
@@ -118,9 +118,14 @@ * `#memlog` controls which processes are profiled. It's also possible to manually specify the process via the interface at `chrome://memory-internals`. -* `#memlog-sampling` will greatly reduce the overhead of the heap profiler, at - the expense of inaccuracy in small or infrequent allocations. Unless - performance is a concern, leave it disabled. +* `#memlog-in-process` makes the profiling service to be run within the + Chrome browser process. Defaults to run the service as a separate dedicated + process. +* `#memlog-sampling-rate` specifies the sampling interval in bytes. The lower + the interval, the more precise is the profile. However it comes at the cost of + performance. Default value is 100KB, that is enough to observe allocation + sites that make allocations >500KB total, where total equals to a single + allocation size times the number of such allocations at the same call site. * `#memlog-stack-mode` describes the type of metadata recorded for each allocation. `native` stacks provide the most utility. The only time the other options should be considered is for Android official builds, most of which do
diff --git a/extensions/browser/api/messaging/BUILD.gn b/extensions/browser/api/messaging/BUILD.gn index a5adc40b..d67b942 100644 --- a/extensions/browser/api/messaging/BUILD.gn +++ b/extensions/browser/api/messaging/BUILD.gn
@@ -9,6 +9,8 @@ source_set("messaging") { sources = [ + "channel_endpoint.cc", + "channel_endpoint.h", "extension_message_port.cc", "extension_message_port.h", "message_port.cc",
diff --git a/extensions/browser/api/messaging/channel_endpoint.cc b/extensions/browser/api/messaging/channel_endpoint.cc new file mode 100644 index 0000000..e64d3a4 --- /dev/null +++ b/extensions/browser/api/messaging/channel_endpoint.cc
@@ -0,0 +1,72 @@ +// Copyright 2019 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 "extensions/browser/api/messaging/channel_endpoint.h" + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/common/child_process_host.h" +#include "extensions/browser/process_manager.h" +#include "extensions/common/constants.h" + +namespace extensions { + +ChannelEndpoint::ChannelEndpoint(content::BrowserContext* browser_context, + int render_process_id, + const PortContext& port_context) + : browser_context_(browser_context), + render_process_id_(render_process_id), + port_context_(port_context) { + // Context must be exclusive to render frame or worker. + DCHECK_NE(port_context.is_for_service_worker(), + port_context.is_for_render_frame()); +} + +// For native message endpoint. +ChannelEndpoint::ChannelEndpoint(content::BrowserContext* browser_context) + : browser_context_(browser_context), + render_process_id_(content::ChildProcessHost::kInvalidUniqueID) { + DCHECK(!port_context_.is_for_render_frame() && + !port_context_.is_for_service_worker()); +} + +bool ChannelEndpoint::is_for_service_worker() const { + return port_context_.is_for_service_worker(); +} + +bool ChannelEndpoint::is_for_render_frame() const { + return port_context_.frame.has_value(); +} + +bool ChannelEndpoint::is_for_native_host() const { + return !port_context_.is_for_render_frame() && + !port_context_.is_for_service_worker(); +} + +content::RenderFrameHost* ChannelEndpoint::GetRenderFrameHost() const { + DCHECK(port_context_.is_for_render_frame()); + return content::RenderFrameHost::FromID(render_process_id_, + port_context_.frame->routing_id); +} + +WorkerId ChannelEndpoint::GetWorkerId() const { + DCHECK(port_context_.is_for_service_worker()); + return {port_context_.worker->extension_id, render_process_id_, + port_context_.worker->version_id, port_context_.worker->thread_id}; +} + +bool ChannelEndpoint::IsValid() const { + if (is_for_service_worker()) { + return ProcessManager::Get(browser_context()) + ->HasServiceWorker(GetWorkerId()); + } + + if (is_for_render_frame()) + return GetRenderFrameHost() != nullptr; + + DCHECK(is_for_native_host()); + return true; +} + +} // namespace extensions
diff --git a/extensions/browser/api/messaging/channel_endpoint.h b/extensions/browser/api/messaging/channel_endpoint.h new file mode 100644 index 0000000..62d6e87 --- /dev/null +++ b/extensions/browser/api/messaging/channel_endpoint.h
@@ -0,0 +1,60 @@ +// Copyright 2019 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_API_MESSAGING_CHANNEL_ENDPOINT_H_ +#define EXTENSIONS_BROWSER_API_MESSAGING_CHANNEL_ENDPOINT_H_ + +#include "extensions/browser/service_worker/worker_id.h" + +#include "extensions/common/api/messaging/port_context.h" + +namespace content { +class BrowserContext; +class RenderFrameHost; +} // namespace content + +namespace extensions { + +// Represents an endpoint (tab, frame or worker) of a message channel in a +// render process. +// TODO(crbug.com/939594): Consolidate all classes/structs around extension +// message ports. +class ChannelEndpoint { + public: + // An endpoint for a PortContext. + ChannelEndpoint(content::BrowserContext* browser_context, + int render_process_id, + const PortContext& port_context); + // An endpoint for a native message host. + ChannelEndpoint(content::BrowserContext* browser_context); + + content::BrowserContext* browser_context() const { return browser_context_; } + int render_process_id() const { return render_process_id_; } + const PortContext& port_context() const { return port_context_; } + + bool is_for_service_worker() const; + bool is_for_render_frame() const; + bool is_for_native_host() const; + + // If the endpoint is a Service Worker, returns its worker id. + // Only valid for worker endpoint. + WorkerId GetWorkerId() const; + + // Returns the render frame if this endpoint points to a frame. Returns + // nullptr if the frame is no longer alive. + // Only valid for frame endpoint. + content::RenderFrameHost* GetRenderFrameHost() const; + + // Returns whether the endpoint is currently live. + bool IsValid() const; + + private: + content::BrowserContext* const browser_context_; + const int render_process_id_; + const PortContext port_context_; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_MESSAGING_CHANNEL_ENDPOINT_H_
diff --git a/extensions/browser/api/messaging/extension_message_port.cc b/extensions/browser/api/messaging/extension_message_port.cc index b57e4b70..a74181f 100644 --- a/extensions/browser/api/messaging/extension_message_port.cc +++ b/extensions/browser/api/messaging/extension_message_port.cc
@@ -17,6 +17,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/process_manager_observer.h" @@ -186,6 +187,35 @@ } } +ExtensionMessagePort::ExtensionMessagePort( + base::WeakPtr<ChannelDelegate> channel_delegate, + const PortId& port_id, + content::BrowserContext* browser_context) + : weak_channel_delegate_(channel_delegate), + port_id_(port_id), + browser_context_(browser_context) {} + +// static +std::unique_ptr<ExtensionMessagePort> ExtensionMessagePort::CreateForEndpoint( + base::WeakPtr<ChannelDelegate> channel_delegate, + const PortId& port_id, + const std::string& extension_id, + const ChannelEndpoint& endpoint, + bool include_child_frames) { + if (endpoint.is_for_render_frame()) { + return std::make_unique<ExtensionMessagePort>( + channel_delegate, port_id, extension_id, endpoint.GetRenderFrameHost(), + include_child_frames); + } + DCHECK(!include_child_frames); + // NOTE: We don't want all the workers within the extension, so we cannot + // reuse other constructor from above. + std::unique_ptr<ExtensionMessagePort> port(new ExtensionMessagePort( + channel_delegate, port_id, endpoint.browser_context())); + port->RegisterWorker(endpoint.GetWorkerId()); + return port; +} + ExtensionMessagePort::~ExtensionMessagePort() {} void ExtensionMessagePort::RemoveCommonFrames(const MessagePort& port) {
diff --git a/extensions/browser/api/messaging/extension_message_port.h b/extensions/browser/api/messaging/extension_message_port.h index cbaf656..a747f5cf 100644 --- a/extensions/browser/api/messaging/extension_message_port.h +++ b/extensions/browser/api/messaging/extension_message_port.h
@@ -30,6 +30,7 @@ namespace extensions { class ExtensionHost; +class ChannelEndpoint; struct PortContext; // A port that manages communication with an extension. @@ -49,6 +50,16 @@ const PortId& port_id, const std::string& extension_id, content::RenderProcessHost* extension_process); + + // Creates a port for any ChannelEndpoint which can be for a render frame or + // Service Worker. + static std::unique_ptr<ExtensionMessagePort> CreateForEndpoint( + base::WeakPtr<ChannelDelegate> channel_delegate, + const PortId& port_id, + const std::string& extension_id, + const ChannelEndpoint& endpoint, + bool include_child_frames); + ~ExtensionMessagePort() override; // MessagePort: @@ -75,6 +86,10 @@ class FrameTracker; struct IPCTarget; + ExtensionMessagePort(base::WeakPtr<ChannelDelegate> channel_delegate, + const PortId& port_id, + content::BrowserContext* browser_context); + // Registers a frame as a receiver / sender. void RegisterFrame(content::RenderFrameHost* rfh);
diff --git a/extensions/browser/api/messaging/message_service.cc b/extensions/browser/api/messaging/message_service.cc index 621334e..59237f2 100644 --- a/extensions/browser/api/messaging/message_service.cc +++ b/extensions/browser/api/messaging/message_service.cc
@@ -27,6 +27,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/child_process_host.h" #include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" #include "extensions/browser/api/messaging/extension_message_port.h" #include "extensions/browser/api/messaging/message_port.h" #include "extensions/browser/api/messaging/messaging_delegate.h" @@ -85,8 +86,7 @@ }; struct MessageService::OpenChannelParams { - int source_process_id; - int source_routing_id; + ChannelEndpoint source; std::unique_ptr<base::DictionaryValue> source_tab; int source_frame_id; std::unique_ptr<MessagePort> receiver; @@ -99,8 +99,7 @@ bool include_guest_process_info; // Takes ownership of receiver. - OpenChannelParams(int source_process_id, - int source_routing_id, + OpenChannelParams(const ChannelEndpoint& source, std::unique_ptr<base::DictionaryValue> source_tab, int source_frame_id, MessagePort* receiver, @@ -111,8 +110,7 @@ const GURL& source_url, const std::string& channel_name, bool include_guest_process_info) - : source_process_id(source_process_id), - source_routing_id(source_routing_id), + : source(source), source_tab(std::move(source_tab)), source_frame_id(source_frame_id), receiver(receiver), @@ -171,8 +169,7 @@ } void MessageService::OpenChannelToExtension( - int source_process_id, - int source_routing_id, + const ChannelEndpoint& source, const PortId& source_port_id, const MessagingEndpoint& source_endpoint, std::unique_ptr<MessagePort> opener_port, @@ -187,15 +184,17 @@ source_endpoint.type == MessagingEndpoint::Type::kNativeApp); DCHECK_EQ(source_endpoint.native_app_name.has_value(), source_endpoint.type == MessagingEndpoint::Type::kNativeApp); + int source_process_id = source.render_process_id(); DCHECK_EQ(source_process_id == content::ChildProcessHost::kInvalidUniqueID, source_endpoint.type == MessagingEndpoint::Type::kNativeApp); + const PortContext& source_context = source.port_context(); + DCHECK(!source_context.is_for_service_worker()) + << "Service worker to extension messaging isn't supported yet."; content::RenderFrameHost* source_render_frame_host = nullptr; BrowserContext* context = context_; if (source_process_id != content::ChildProcessHost::kInvalidUniqueID) { - DCHECK_NE(source_routing_id, MSG_ROUTING_NONE); - source_render_frame_host = - content::RenderFrameHost::FromID(source_process_id, source_routing_id); + source_render_frame_host = source.GetRenderFrameHost(); if (!source_render_frame_host) return; context = source_render_frame_host->GetProcess()->GetBrowserContext(); @@ -291,10 +290,10 @@ } std::unique_ptr<OpenChannelParams> params(new OpenChannelParams( - source_process_id, source_routing_id, std::move(source_tab), - source_frame_id, nullptr, source_port_id.GetOppositePortId(), - source_endpoint, std::move(opener_port), target_extension_id, source_url, - channel_name, include_guest_process_info)); + source, std::move(source_tab), source_frame_id, nullptr, + source_port_id.GetOppositePortId(), source_endpoint, + std::move(opener_port), target_extension_id, source_url, channel_name, + include_guest_process_info)); pending_incognito_channels_[params->receiver_port_id.GetChannelId()] = PendingMessagesQueue(); @@ -427,8 +426,7 @@ #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) } -void MessageService::OpenChannelToTab(int source_process_id, - int source_routing_id, +void MessageService::OpenChannelToTab(const ChannelEndpoint& source, const PortId& source_port_id, int tab_id, int frame_id, @@ -438,18 +436,18 @@ DCHECK_GE(frame_id, -1); DCHECK(source_port_id.is_opener); - content::RenderFrameHost* source = - content::RenderFrameHost::FromID(source_process_id, source_routing_id); - if (!source) + // RenderFrameHost or the worker thread might be gone. + if (!source.IsValid()) return; - auto opener_port = std::make_unique<ExtensionMessagePort>( - weak_factory_.GetWeakPtr(), source_port_id, extension_id, source, - false /* include_child_frames */); + std::unique_ptr<ExtensionMessagePort> opener_port = + ExtensionMessagePort::CreateForEndpoint( + weak_factory_.GetWeakPtr(), source_port_id, extension_id, source, + false /* include_child_frames */); if (!opener_port->IsValidPort()) return; - BrowserContext* source_context = source->GetProcess()->GetBrowserContext(); + BrowserContext* source_context = source.browser_context(); DCHECK( ExtensionsBrowserClient::Get()->IsSameContext(source_context, context_)); content::WebContents* receiver_contents = @@ -484,7 +482,7 @@ DCHECK(ExtensionsBrowserClient::Get()->IsSameContext(receiver_context, context_)); std::unique_ptr<OpenChannelParams> params(new OpenChannelParams( - source_process_id, source_routing_id, + source, std::unique_ptr<base::DictionaryValue>(), // Source tab doesn't make // sense // for opening to tabs. @@ -509,14 +507,9 @@ DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty()); // Check whether the source got closed while in flight. - content::RenderFrameHost* source = nullptr; - if (params->source_process_id != - content::ChildProcessHost::kInvalidUniqueID) { - source = content::RenderFrameHost::FromID(params->source_process_id, - params->source_routing_id); - if (!source) - return; - } + const ChannelEndpoint& source = params->source; + if (!source.IsValid()) + return; // Closed while in flight. if (!params->opener_port->IsValidPort()) return; @@ -525,11 +518,8 @@ return; } - // TODO(crbug.com/925918): Implement opening channel from from a Service - // Worker context. - params->opener_port->OpenPort( - params->source_process_id, - PortContext::ForFrame(params->source_routing_id)); + const PortContext& port_context = source.port_context(); + params->opener_port->OpenPort(source.render_process_id(), port_context); params->opener_port->RevalidatePort(); params->receiver->RemoveCommonFrames(*params->opener_port); @@ -547,12 +537,15 @@ int guest_process_id = content::ChildProcessHost::kInvalidUniqueID; int guest_render_frame_routing_id = MSG_ROUTING_NONE; - if (params->include_guest_process_info) { - guest_process_id = params->source_process_id; - guest_render_frame_routing_id = params->source_routing_id; + if (params->include_guest_process_info && + // TODO(lazyboy): Investigate <webview> SW messaging. + source.is_for_render_frame()) { + guest_process_id = params->source.render_process_id(); + DCHECK(port_context.frame); + guest_render_frame_routing_id = port_context.frame->routing_id; DCHECK(WebViewGuest::FromWebContents( - WebContents::FromRenderFrameHost(source))); + WebContents::FromRenderFrameHost(source.GetRenderFrameHost()))); } // Send the connect event to the receiver. Give it the opener's port ID (the @@ -792,11 +785,10 @@ ChannelId channel_id = (*params)->receiver_port_id.GetChannelId(); pending_lazy_context_channels_.emplace(channel_id, context_id); - int source_id = (*params)->source_process_id; task_queue->AddPendingTask( - context_id, base::BindOnce(&MessageService::PendingLazyContextOpenChannel, - weak_factory_.GetWeakPtr(), - base::Passed(params), source_id)); + context_id, + base::BindOnce(&MessageService::PendingLazyContextOpenChannel, + weak_factory_.GetWeakPtr(), std::move(*params))); for (const PendingMessage& message : pending_messages) { EnqueuePendingMessageForLazyBackgroundLoad(message.first, channel_id, @@ -822,15 +814,11 @@ pending_incognito_channels_.erase(pending_for_incognito); // Check whether the source got closed while in flight. - content::RenderFrameHost* source = nullptr; - if (params->source_process_id != - content::ChildProcessHost::kInvalidUniqueID) { - DCHECK_NE(params->source_routing_id, MSG_ROUTING_NONE); - source = content::RenderFrameHost::FromID(params->source_process_id, - params->source_routing_id); - if (!source) - return; - } + const ChannelEndpoint& source = params->source; + // Re-lookup the source process since it may no longer be valid. + if (!source.IsValid()) + return; + if (!params->opener_port->IsValidPort()) return; @@ -839,10 +827,7 @@ return; } - content::RenderProcessHost* source_process = - source ? source->GetProcess() : nullptr; - BrowserContext* context = - source_process ? source_process->GetBrowserContext() : context_; + BrowserContext* context = source.browser_context(); DCHECK(ExtensionsBrowserClient::Get()->IsSameContext(context, context_)); // Note: we use the source's profile here. If the source is an incognito @@ -879,7 +864,6 @@ void MessageService::PendingLazyContextOpenChannel( std::unique_ptr<OpenChannelParams> params, - int source_process_id, std::unique_ptr<LazyContextTaskQueue::ContextInfo> context_info) { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/extensions/browser/api/messaging/message_service.h b/extensions/browser/api/messaging/message_service.h index 5106df8..280b9b7 100644 --- a/extensions/browser/api/messaging/message_service.h +++ b/extensions/browser/api/messaging/message_service.h
@@ -30,6 +30,7 @@ } namespace extensions { +class ChannelEndpoint; class Extension; class ExtensionHost; class MessagingDelegate; @@ -81,8 +82,7 @@ // and every listening context owned by that extension. |channel_name| is // an optional identifier for use by extension developers. |opener_port| is an // optional pre-opened port that should be attached to the opened channel. - void OpenChannelToExtension(int source_process_id, - int source_routing_id, + void OpenChannelToExtension(const ChannelEndpoint& source, const PortId& source_port_id, const MessagingEndpoint& source_endpoint, std::unique_ptr<MessagePort> opener_port, @@ -93,8 +93,7 @@ // Same as above, but opens a channel to the tab with the given ID. Messages // are restricted to that tab, so if there are multiple tabs in that process, // only the targeted tab will receive messages. - void OpenChannelToTab(int source_process_id, - int source_routing_id, + void OpenChannelToTab(const ChannelEndpoint& source, const PortId& source_port_id, int tab_id, int frame_id, @@ -206,7 +205,6 @@ // use that argument. void PendingLazyContextOpenChannel( std::unique_ptr<OpenChannelParams> params, - int source_process_id, std::unique_ptr<LazyContextTaskQueue::ContextInfo> context_info); void PendingLazyContextClosePort( const PortId& port_id,
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index 24039e6..4aad402 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/debug/alias.h" #include "base/debug/dump_without_crashing.h" +#include "base/feature_list.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" @@ -19,7 +20,9 @@ #include "extensions/browser/extension_navigation_ui_data.h" #include "extensions/common/manifest_handlers/web_accessible_resources_info.h" #include "net/http/http_util.h" +#include "services/network/public/cpp/features.h" #include "third_party/blink/public/platform/resource_request_blocked_reason.h" +#include "url/origin.h" namespace extensions { @@ -36,6 +39,7 @@ network::mojom::URLLoaderClientPtr client) : factory_(factory), request_(request), + original_initiator_(request.request_initiator), is_download_(is_download), request_id_(request_id), network_service_request_id_(network_service_request_id), @@ -79,11 +83,16 @@ request_completed_ = false; // Derive a new WebRequestInfo value any time |Restart()| is called, because // the details in |request_| may have changed e.g. if we've been redirected. + // |request_initiator| can be modified on redirects, but we keep the original + // for |initiator| in the event. See also + // https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest. + network::ResourceRequest request_for_info = request_; + request_for_info.request_initiator = original_initiator_; info_.emplace( request_id_, factory_->render_process_id_, request_.render_frame_id, factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy() : nullptr, - routing_id_, factory_->resource_context_, request_, is_download_, + routing_id_, factory_->resource_context_, request_for_info, is_download_, !(options_ & network::mojom::kURLLoadOptionSynchronous)); current_request_uses_header_client_ = @@ -359,19 +368,37 @@ "Location: %s\n" "Non-Authoritative-Reason: WebRequest API\n\n", kInternalRedirectStatusCode, redirect_url_.spec().c_str()); - std::string http_origin; - if (request_.headers.GetHeader("Origin", &http_origin)) { + + if (base::FeatureList::IsEnabled(network::features::kOutOfBlinkCors)) { + // Cross-origin requests need to modify the Origin header to 'null'. Since + // CorsURLLoader sets |request_initiator| to the Origin request header in + // NetworkService, we need to modify |request_initiator| here to craft the + // Origin header indirectly. + // Following checks implement the step 10 of "4.4. HTTP-redirect fetch", + // https://fetch.spec.whatwg.org/#http-redirect-fetch + if (request_.request_initiator && + (!url::Origin::Create(redirect_url_) + .IsSameOriginWith(url::Origin::Create(request_.url)) && + !request_.request_initiator->IsSameOriginWith( + url::Origin::Create(request_.url)))) { + // Reset the initiator to pretend tainted origin flag of the spec is set. + request_.request_initiator = url::Origin(); + } + } else { // If this redirect is used in a cross-origin request, add CORS headers to - // make sure that the redirect gets through. Note that the destination URL - // is still subject to the usual CORS policy, i.e. the resource will only - // be available to web pages if the server serves the response with the - // required CORS response headers. - // Matches the behavior in url_request_redirect_job.cc. - headers += base::StringPrintf( - "\n" - "Access-Control-Allow-Origin: %s\n" - "Access-Control-Allow-Credentials: true", - http_origin.c_str()); + // make sure that the redirect gets through the Blink CORS. Note that the + // destination URL is still subject to the usual CORS policy, i.e. the + // resource will only be available to web pages if the server serves the + // response with the required CORS response headers. Matches the behavior in + // url_request_redirect_job.cc. + std::string http_origin; + if (request_.headers.GetHeader("Origin", &http_origin)) { + headers += base::StringPrintf( + "\n" + "Access-Control-Allow-Origin: %s\n" + "Access-Control-Allow-Credentials: true", + http_origin.c_str()); + } } head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length()));
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index d38dfe4..89477505 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -124,6 +124,7 @@ WebRequestProxyingURLLoaderFactory* const factory_; network::ResourceRequest request_; + const base::Optional<url::Origin> original_initiator_; const bool is_download_; const uint64_t request_id_; const int32_t network_service_request_id_;
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index 0714c6335..8cc9503 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc
@@ -336,24 +336,30 @@ // events for other extensions have been acked. Make sure that the event id // sent by the renderer is one that this ExtensionHost expects to receive. // This way if a renderer _is_ compromised, it can really only affect itself. - const auto it = unacked_messages_.find(event_id); - if (!is_background_page || it == unacked_messages_.end()) { + if (!is_background_page) { // Kill this renderer. DCHECK(render_process_host()); - if (!is_background_page) { - LOG(ERROR) << "Killing renderer for extension " << extension_id() - << " for sending an EventAck without a lazy background page."; - } else { - // We have received an unexpected event id from the renderer. It might - // be compromised or it might have some other issue. - LOG(ERROR) << "Killing renderer for extension " << extension_id() - << " for sending an EventAck message with a bad event id."; - } + LOG(ERROR) << "Killing renderer for extension " << extension_id() + << " for sending an EventAck without a lazy background page."; bad_message::ReceivedBadMessage(render_process_host(), bad_message::EH_BAD_EVENT_ID); return; } + const auto it = unacked_messages_.find(event_id); + if (it == unacked_messages_.end()) { + // Ideally, we'd be able to kill the renderer in the case of it sending an + // ack for an event that we haven't seen. However, https://crbug.com/939279 + // demonstrates that there are cases in which this can happen in other + // situations. We should track those down and fix them, but for now + // log and gracefully exit. + // bad_message::ReceivedBadMessage(render_process_host(), + // bad_message::EH_BAD_EVENT_ID); + LOG(ERROR) << "Received EventAck for extension " << extension_id() + << " for an unknown event."; + return; + } + EventRouter* router = EventRouter::Get(browser_context_); if (router) router->OnEventAck(browser_context_, extension_id(), it->second);
diff --git a/extensions/browser/extension_message_filter.cc b/extensions/browser/extension_message_filter.cc index 4e8ac3a..21d39287 100644 --- a/extensions/browser/extension_message_filter.cc +++ b/extensions/browser/extension_message_filter.cc
@@ -10,6 +10,7 @@ #include "components/crx_file/id_util.h" #include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h" #include "content/public/browser/render_process_host.h" +#include "extensions/browser/api/messaging/channel_endpoint.h" #include "extensions/browser/api/messaging/message_service.h" #include "extensions/browser/bad_message.h" #include "extensions/browser/blob_holder.h" @@ -400,11 +401,12 @@ // TODO(crbug.com/925918): Support messages from Service Worker. DCHECK(source_context.is_for_render_frame()); if (browser_context_) { + ChannelEndpoint source_endpoint(browser_context_, render_process_id_, + source_context); MessageService::Get(browser_context_) - ->OpenChannelToExtension( - render_process_id_, source_context.frame->routing_id, port_id, - info.source_endpoint, nullptr /* opener_port */, info.target_id, - info.source_url, channel_name); + ->OpenChannelToExtension(source_endpoint, port_id, info.source_endpoint, + nullptr /* opener_port */, info.target_id, + info.source_url, channel_name); } } @@ -431,15 +433,14 @@ const std::string& channel_name, const PortId& port_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - // TODO(crbug.com/925918): Support messages from Service Worker. - DCHECK(source_context.is_for_render_frame()); if (!browser_context_) return; + ChannelEndpoint source_endpoint(browser_context_, render_process_id_, + source_context); MessageService::Get(browser_context_) - ->OpenChannelToTab(render_process_id_, source_context.frame->routing_id, - port_id, info.tab_id, info.frame_id, extension_id, - channel_name); + ->OpenChannelToTab(source_endpoint, port_id, info.tab_id, info.frame_id, + extension_id, channel_name); } void ExtensionMessageFilter::OnOpenMessagePort(const PortContext& source,
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index bdd7848..f787d076 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -936,6 +936,7 @@ void Dispatcher::OnDeliverMessage(int worker_thread_id, const PortId& target_port_id, const Message& message) { + DCHECK_EQ(kMainThreadId, worker_thread_id); bindings_system_->GetMessagingService()->DeliverMessage( script_context_set_.get(), target_port_id, message, NULL); // All render frames.
diff --git a/extensions/renderer/ipc_message_sender.cc b/extensions/renderer/ipc_message_sender.cc index 81a11aeb..04f71f8 100644 --- a/extensions/renderer/ipc_message_sender.cc +++ b/extensions/renderer/ipc_message_sender.cc
@@ -364,9 +364,16 @@ PortContextForCurrentWorker(), info, channel_name, port_id)); break; } - case MessageTarget::TAB: - NOTIMPLEMENTED() << "https://crbug.com/925918."; + case MessageTarget::TAB: { + DCHECK(extension); + ExtensionMsg_TabTargetConnectionInfo info; + info.tab_id = *target.tab_id; + info.frame_id = *target.frame_id; + dispatcher_->Send(new ExtensionHostMsg_OpenChannelToTab( + PortContextForCurrentWorker(), info, extension->id(), channel_name, + port_id)); break; + } case MessageTarget::NATIVE_APP: NOTIMPLEMENTED() << "https://crbug.com/925918."; break;
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc index 7cba7369..ca80343 100644 --- a/extensions/renderer/messaging_bindings.cc +++ b/extensions/renderer/messaging_bindings.cc
@@ -23,13 +23,17 @@ #include "extensions/common/api/messaging/port_context.h" #include "extensions/common/api/messaging/port_id.h" #include "extensions/common/extension_messages.h" +#include "extensions/renderer/extension_bindings_system.h" #include "extensions/renderer/extension_frame_helper.h" #include "extensions/renderer/extension_port.h" #include "extensions/renderer/gc_callback.h" +#include "extensions/renderer/ipc_message_sender.h" +#include "extensions/renderer/message_target.h" #include "extensions/renderer/messaging_util.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/script_context_set.h" #include "extensions/renderer/v8_helpers.h" +#include "extensions/renderer/worker_thread_dispatcher.h" #include "extensions/renderer/worker_thread_util.h" #include "gin/converter.h" #include "third_party/blink/public/web/web_user_gesture_indicator.h" @@ -53,6 +57,11 @@ base::LazyInstance<std::map<ScriptContext*, MessagingBindings*>>:: DestructorAtExit g_messaging_map = LAZY_INSTANCE_INITIALIZER; +IPCMessageSender* GetWorkerThreadIPCMessageSender() { + DCHECK(worker_thread_util::IsWorkerThread()); + return WorkerThreadDispatcher::GetBindingsSystem()->GetIPCMessageSender(); +} + } // namespace MessagingBindings::MessagingBindings(ScriptContext* context) @@ -261,11 +270,10 @@ void MessagingBindings::OpenChannelToTab( const v8::FunctionCallbackInfo<v8::Value>& args) { - // TODO(crbug.com/925918): Support Service worker to tab messaging. - DCHECK(!worker_thread_util::IsWorkerThread()); - content::RenderFrame* render_frame = context()->GetRenderFrame(); - if (!render_frame) + bool is_for_service_worker = false; + if (!render_frame && + !(is_for_service_worker = worker_thread_util::IsWorkerThread())) return; DCHECK_NE(context()->context_type(), Feature::CONTENT_SCRIPT_CONTEXT); @@ -295,14 +303,23 @@ std::string extension_id = *v8::String::Utf8Value(isolate, args[2]); std::string channel_name = *v8::String::Utf8Value(isolate, args[3]); - ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); - DCHECK(frame_helper); + if (!is_for_service_worker) { + ExtensionFrameHelper* frame_helper = + ExtensionFrameHelper::Get(render_frame); + DCHECK(frame_helper); + } { SCOPED_UMA_HISTOGRAM_TIMER("Extensions.Messaging.SetPortIdTime.Tab"); - render_frame->Send(new ExtensionHostMsg_OpenChannelToTab( - PortContext::ForFrame(render_frame->GetRoutingID()), info, extension_id, - channel_name, port_id)); + if (is_for_service_worker) { + GetWorkerThreadIPCMessageSender()->SendOpenMessageChannel( + context(), port_id, MessageTarget::ForTab(info.tab_id, info.frame_id), + channel_name, false /* include_tls_channel_id */); + } else { + render_frame->Send(new ExtensionHostMsg_OpenChannelToTab( + PortContext::ForFrame(render_frame->GetRoutingID()), info, + extension_id, channel_name, port_id)); + } } args.GetReturnValue().Set(static_cast<int32_t>(js_id));
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index 89290eb..9b6ab9f 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -292,6 +292,7 @@ sources += [ "command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc" ] } else if (is_mac) { libs += [ "IOSurface.framework" ] + sources += [ "command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc" ] } else if (is_win) { deps += [ "//ui/platform_window",
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc index 129446b6..832dad31 100644 --- a/gpu/command_buffer/client/raster_implementation.cc +++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -29,7 +29,6 @@ #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/decode_stashing_image_provider.h" #include "cc/paint/display_item_list.h" #include "cc/paint/paint_cache.h"
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc index 143cfdc..8c6b378 100644 --- a/gpu/command_buffer/client/raster_implementation_gles.cc +++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -12,7 +12,6 @@ #include <vector> #include "base/logging.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/decode_stashing_image_provider.h" #include "cc/paint/display_item_list.h" // nogncheck #include "cc/paint/paint_op_buffer_serializer.h"
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc index 324fc46..6e0ac73 100644 --- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc +++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -13,7 +13,6 @@ #include <vector> #include "base/containers/flat_map.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/display_item_list.h" #include "cc/paint/image_provider.h" #include "components/viz/common/resources/resource_format_utils.h"
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn index c33ac92..6955858 100644 --- a/gpu/command_buffer/service/BUILD.gn +++ b/gpu/command_buffer/service/BUILD.gn
@@ -332,8 +332,14 @@ } if (is_mac) { + sources += [ + "shared_image_backing_factory_iosurface.h", + "shared_image_backing_factory_iosurface.mm", + ] + # Required by gles2_cmd_decoder.cc on Mac. libs = [ + "Cocoa.framework", "IOSurface.framework", "OpenGL.framework", ]
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index f11190a6..e692207b 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -262,15 +262,6 @@ disallowed_features_ = disallowed_features; context_type_ = context_type; is_passthrough_cmd_decoder_ = is_passthrough_cmd_decoder; - switch (context_type) { - case CONTEXT_TYPE_WEBGL1: - case CONTEXT_TYPE_OPENGLES2: - break; - default: - // https://crbug.com/826509 - workarounds_.use_client_side_arrays_for_stream_buffers = false; - break; - } InitializeFeatures(); initialized_ = true; }
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index f3409215e..ca61ad0c 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -1440,23 +1440,6 @@ EXPECT_TRUE(info_->validators()->index_type.IsValid(GL_UNSIGNED_INT)); } -TEST_P(FeatureInfoTest, InitializeVAOsWithClientSideArrays) { - gpu::GpuDriverBugWorkarounds workarounds; - workarounds.use_client_side_arrays_for_stream_buffers = true; - SetupInitExpectationsWithWorkarounds("GL_OES_vertex_array_object", - workarounds); - if (GetContextType() == CONTEXT_TYPE_OPENGLES2) { - EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers); - EXPECT_FALSE(info_->feature_flags().native_vertex_array_object); - } else { // CONTEXT_TYPE_OPENGLES3 - // We only turn on use_client_side_arrays_for_stream_buffers on ES2 - // contexts. See https://crbug.com/826509. - EXPECT_FALSE( - info_->workarounds().use_client_side_arrays_for_stream_buffers); - EXPECT_TRUE(info_->feature_flags().native_vertex_array_object); - } -} - TEST_P(FeatureInfoTest, InitializeEXT_blend_minmax) { SetupInitExpectations("GL_EXT_blend_minmax"); EXPECT_TRUE(gfx::HasExtension(info_->extensions(), "GL_EXT_blend_minmax"));
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 164b75a..21f408fb 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -23,7 +23,6 @@ #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/paint_cache.h" #include "cc/paint/paint_op_buffer.h" #include "cc/paint/transfer_cache_entry.h"
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc index 310413e3..067fbaf 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -38,15 +38,16 @@ namespace { +using UnpackStateAttribs = + SharedImageBackingFactoryGLTexture::UnpackStateAttribs; + class ScopedResetAndRestoreUnpackState { public: ScopedResetAndRestoreUnpackState(gl::GLApi* api, - bool es3_capable, - bool desktop_gl, - bool supports_unpack_subimage, + const UnpackStateAttribs& attribs, bool uploading_data) : api_(api) { - if (es3_capable) { + if (attribs.es3_capable) { // Need to unbind any GL_PIXEL_UNPACK_BUFFER for the nullptr in // glTexImage2D to mean "no pixels" (as opposed to offset 0 in the // buffer). @@ -59,7 +60,7 @@ if (unpack_alignment_ != 4) api_->glPixelStoreiFn(GL_UNPACK_ALIGNMENT, 4); - if (es3_capable || supports_unpack_subimage) { + if (attribs.es3_capable || attribs.supports_unpack_subimage) { api_->glGetIntegervFn(GL_UNPACK_ROW_LENGTH, &unpack_row_length_); if (unpack_row_length_) api_->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, 0); @@ -71,7 +72,7 @@ api_->glPixelStoreiFn(GL_UNPACK_SKIP_PIXELS, 0); } - if (es3_capable) { + if (attribs.es3_capable) { api_->glGetIntegervFn(GL_UNPACK_SKIP_IMAGES, &unpack_skip_images_); if (unpack_skip_images_) api_->glPixelStoreiFn(GL_UNPACK_SKIP_IMAGES, 0); @@ -80,7 +81,7 @@ api_->glPixelStoreiFn(GL_UNPACK_IMAGE_HEIGHT, 0); } - if (desktop_gl) { + if (attribs.desktop_gl) { api->glGetBooleanvFn(GL_UNPACK_SWAP_BYTES, &unpack_swap_bytes_); if (unpack_swap_bytes_) api->glPixelStoreiFn(GL_UNPACK_SWAP_BYTES, GL_FALSE); @@ -231,11 +232,30 @@ scoped_refptr<gles2::TexturePassthrough> texture_passthrough_; }; +class SharedImageBackingWithReadAccess : public SharedImageBacking { + public: + SharedImageBackingWithReadAccess(const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage, + size_t estimated_size) + : SharedImageBacking(mailbox, + format, + size, + color_space, + usage, + estimated_size) {} + ~SharedImageBackingWithReadAccess() override = default; + + virtual void BeginReadAccess() = 0; +}; + class SharedImageRepresentationSkiaImpl : public SharedImageRepresentationSkia { public: SharedImageRepresentationSkiaImpl( SharedImageManager* manager, - SharedImageBacking* backing, + SharedImageBackingWithReadAccess* backing, sk_sp<SkPromiseImageTexture> cached_promise_texture, MemoryTypeTracker* tracker, GLenum target, @@ -286,6 +306,8 @@ sk_sp<SkPromiseImageTexture> BeginReadAccess(SkSurface* sk_surface) override { CheckContext(); + static_cast<SharedImageBackingWithReadAccess*>(backing()) + ->BeginReadAccess(); return promise_texture_; } @@ -312,21 +334,23 @@ // Implementation of SharedImageBacking that creates a GL Texture and stores it // as a gles2::Texture. Can be used with the legacy mailbox implementation. -class SharedImageBackingGLTexture : public SharedImageBacking { +class SharedImageBackingGLTexture : public SharedImageBackingWithReadAccess { public: SharedImageBackingGLTexture(const Mailbox& mailbox, viz::ResourceFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, uint32_t usage, - gles2::Texture* texture) - : SharedImageBacking(mailbox, - format, - size, - color_space, - usage, - texture->estimated_size()), - texture_(texture) { + gles2::Texture* texture, + const UnpackStateAttribs& attribs) + : SharedImageBackingWithReadAccess(mailbox, + format, + size, + color_space, + usage, + texture->estimated_size()), + texture_(texture), + attribs_(attribs) { DCHECK(texture_); } @@ -401,6 +425,29 @@ texture_->DumpLevelMemory(pmd, client_tracing_id, dump_name); } + void BeginReadAccess() override { + GLenum target = texture_->target(); + gles2::Texture::ImageState old_state = gles2::Texture::UNBOUND; + gl::GLImage* image = texture_->GetLevelImage(target, 0, &old_state); + if (image && old_state == gpu::gles2::Texture::UNBOUND) { + gl::GLApi* api = gl::g_current_gl_context; + ScopedRestoreTexture scoped_restore(api, target); + api->glBindTextureFn(target, texture_->service_id()); + gles2::Texture::ImageState new_state = gles2::Texture::UNBOUND; + if (image->ShouldBindOrCopy() == gl::GLImage::BIND) { + if (image->BindTexImage(target)) + new_state = gles2::Texture::BOUND; + } else { + ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs_, + /*upload=*/true); + if (image->CopyTexImage(target)) + new_state = gles2::Texture::COPIED; + } + if (old_state != new_state) + texture_->SetLevelImage(target, 0, image, new_state); + } + } + protected: std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture( SharedImageManager* manager, @@ -473,12 +520,14 @@ gles2::Texture* texture_ = nullptr; gles2::Texture* rgb_emulation_texture_ = nullptr; sk_sp<SkPromiseImageTexture> cached_promise_texture_; + const UnpackStateAttribs attribs_; }; // Implementation of SharedImageBacking that creates a GL Texture and stores it // as a gles2::TexturePassthrough. Can be used with the legacy mailbox // implementation. -class SharedImageBackingPassthroughGLTexture : public SharedImageBacking { +class SharedImageBackingPassthroughGLTexture + : public SharedImageBackingWithReadAccess { public: SharedImageBackingPassthroughGLTexture( const Mailbox& mailbox, @@ -488,12 +537,12 @@ uint32_t usage, scoped_refptr<gles2::TexturePassthrough> passthrough_texture, bool is_cleared) - : SharedImageBacking(mailbox, - format, - size, - color_space, - usage, - passthrough_texture->estimated_size()), + : SharedImageBackingWithReadAccess(mailbox, + format, + size, + color_space, + usage, + passthrough_texture->estimated_size()), texture_passthrough_(std::move(passthrough_texture)), is_cleared_(is_cleared) { DCHECK(texture_passthrough_); @@ -555,6 +604,8 @@ gl_image->OnMemoryDump(pmd, client_tracing_id, dump_name); } + void BeginReadAccess() override {} + protected: std::unique_ptr<SharedImageRepresentationGLTexturePassthrough> ProduceGLTexturePassthrough(SharedImageManager* manager, @@ -610,12 +661,12 @@ gpu_memory_buffer_formats_ = feature_info->feature_flags().gpu_memory_buffer_formats; texture_usage_angle_ = feature_info->feature_flags().angle_texture_usage; - es3_capable_ = feature_info->IsES3Capable(); - desktop_gl_ = !feature_info->gl_version_info().is_es; + attribs.es3_capable = feature_info->IsES3Capable(); + attribs.desktop_gl = !feature_info->gl_version_info().is_es; // Can't use the value from feature_info, as we unconditionally enable this // extension, and assume it can't be used if PBOs are not used (which isn't // true for Skia used direclty against GL). - supports_unpack_subimage_ = + attribs.supports_unpack_subimage = gl::g_current_gl_driver->ext.b_GL_EXT_unpack_subimage; bool enable_texture_storage = feature_info->feature_flags().ext_texture_storage; @@ -811,16 +862,14 @@ size.width(), size.height()); needs_subimage_upload = !pixel_data.empty(); } else if (format_info.is_compressed) { - ScopedResetAndRestoreUnpackState scoped_unpack_state( - api, es3_capable_, desktop_gl_, supports_unpack_subimage_, - !pixel_data.empty()); + ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs, + !pixel_data.empty()); api->glCompressedTexImage2DFn(target, 0, format_info.image_internal_format, size.width(), size.height(), 0, pixel_data.size(), pixel_data.data()); } else { - ScopedResetAndRestoreUnpackState scoped_unpack_state( - api, es3_capable_, desktop_gl_, supports_unpack_subimage_, - !pixel_data.empty()); + ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs, + !pixel_data.empty()); api->glTexImage2DFn(target, 0, format_info.image_internal_format, size.width(), size.height(), 0, format_info.adjusted_format, format_info.gl_type, @@ -830,19 +879,19 @@ // If we are using a buffer or TexStorage API but have data to upload, do so // now via TexSubImage2D. if (needs_subimage_upload) { - ScopedResetAndRestoreUnpackState scoped_unpack_state( - api, es3_capable_, desktop_gl_, supports_unpack_subimage_, - !pixel_data.empty()); + ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs, + !pixel_data.empty()); api->glTexSubImage2DFn(target, 0, 0, 0, size.width(), size.height(), format_info.adjusted_format, format_info.gl_type, pixel_data.data()); } - return MakeBacking( - use_passthrough_, mailbox, target, service_id, image, - gles2::Texture::BOUND, level_info_internal_format, format_info.gl_format, - format_info.gl_type, format_info.swizzle, - pixel_data.empty() ? is_cleared : true, format, size, color_space, usage); + return MakeBacking(use_passthrough_, mailbox, target, service_id, image, + gles2::Texture::BOUND, level_info_internal_format, + format_info.gl_format, format_info.gl_type, + format_info.swizzle, + pixel_data.empty() ? is_cleared : true, format, size, + color_space, usage, attribs); } std::unique_ptr<SharedImageBacking> @@ -928,7 +977,7 @@ return MakeBacking(use_passthrough_, mailbox, target, service_id, image, image_state, internal_format, gl_format, gl_type, nullptr, - true, format, size, color_space, usage); + true, format, size, color_space, usage, attribs); } std::unique_ptr<SharedImageBacking> @@ -944,7 +993,7 @@ gles2::Texture::UNBOUND, viz::GLInternalFormat(format), viz::GLDataFormat(format), viz::GLDataType(format), nullptr, is_cleared, format, size, gfx::ColorSpace(), - usage); + usage, UnpackStateAttribs()); } scoped_refptr<gl::GLImage> SharedImageBackingFactoryGLTexture::MakeGLImage( @@ -988,7 +1037,8 @@ viz::ResourceFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, - uint32_t usage) { + uint32_t usage, + const UnpackStateAttribs& attribs) { if (passthrough) { scoped_refptr<gles2::TexturePassthrough> passthrough_texture = base::MakeRefCounted<gles2::TexturePassthrough>(service_id, target); @@ -1023,7 +1073,7 @@ texture->SetImmutable(true); return std::make_unique<SharedImageBackingGLTexture>( - mailbox, format, size, color_space, usage, texture); + mailbox, format, size, color_space, usage, texture, attribs); } }
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h index 31818fa..43c609f2 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h +++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h
@@ -35,6 +35,12 @@ class GPU_GLES2_EXPORT SharedImageBackingFactoryGLTexture : public SharedImageBackingFactory { public: + struct UnpackStateAttribs { + bool es3_capable = false; + bool desktop_gl = false; + bool supports_unpack_subimage = false; + }; + SharedImageBackingFactoryGLTexture(const GpuPreferences& gpu_preferences, const GpuDriverBugWorkarounds& workarounds, const GpuFeatureInfo& gpu_feature_info, @@ -95,7 +101,8 @@ viz::ResourceFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, - uint32_t usage); + uint32_t usage, + const UnpackStateAttribs& attribs); struct FormatInfo { FormatInfo(); @@ -146,9 +153,7 @@ GpuMemoryBufferFormatSet gpu_memory_buffer_formats_; int32_t max_texture_size_ = 0; bool texture_usage_angle_ = false; - bool es3_capable_ = false; - bool desktop_gl_ = false; - bool supports_unpack_subimage_ = false; + UnpackStateAttribs attribs; }; } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h new file mode 100644 index 0000000..003f059 --- /dev/null +++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.h
@@ -0,0 +1,68 @@ +// Copyright 2019 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 GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_ +#define GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_ + +#include <memory> + +#include "base/macros.h" +#include "components/viz/common/resources/resource_format.h" +#include "gpu/command_buffer/service/shared_image_backing_factory.h" +#include "gpu/gpu_gles2_export.h" +#include "ui/gl/gl_bindings.h" + +namespace gfx { +class Size; +class ColorSpace; +} // namespace gfx + +namespace gpu { +class GpuDriverBugWorkarounds; +struct GpuFeatureInfo; +struct Mailbox; +class SharedImageBacking; + +// Implementation of SharedImageBackingFactory that produce IOSurface backed +// SharedImages. This is meant to be used on macOS only. +class GPU_GLES2_EXPORT SharedImageBackingFactoryIOSurface + : public SharedImageBackingFactory { + public: + SharedImageBackingFactoryIOSurface(const GpuDriverBugWorkarounds& workarounds, + const GpuFeatureInfo& gpu_feature_info); + ~SharedImageBackingFactoryIOSurface() override; + + // SharedImageBackingFactory implementation. + std::unique_ptr<SharedImageBacking> CreateSharedImage( + const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage) override; + std::unique_ptr<SharedImageBacking> CreateSharedImage( + const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage, + base::span<const uint8_t> pixel_data) override; + std::unique_ptr<SharedImageBacking> CreateSharedImage( + const Mailbox& mailbox, + int client_id, + gfx::GpuMemoryBufferHandle handle, + gfx::BufferFormat format, + SurfaceHandle surface_handle, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage) override; + + private: + bool format_supported_by_gl_[viz::RESOURCE_FORMAT_MAX + 1]; + + DISALLOW_COPY_AND_ASSIGN(SharedImageBackingFactoryIOSurface); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm new file mode 100644 index 0000000..c02c4ab --- /dev/null +++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
@@ -0,0 +1,411 @@ +// Copyright 2019 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 "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h" + +#include "base/mac/scoped_cftyperef.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/resource_sizes.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/shared_image_backing.h" +#include "gpu/command_buffer/service/shared_image_representation.h" +#include "gpu/command_buffer/service/skia_utils.h" +#include "gpu/command_buffer/service/texture_manager.h" +#include "third_party/skia/include/core/SkPromiseImageTexture.h" +#include "ui/gfx/mac/io_surface.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_image_io_surface.h" + +namespace gpu { + +namespace { + +struct GLFormatInfo { + bool supported = false; + + // GL internal_format/format/type triplet. + GLuint internal_format = 0; + GLenum format = 0; + GLenum type = 0; +}; + +// Get GL format triplets and modify them to match the logic in +// gl_image_iosurface.mm +GLFormatInfo GetGLFormatInfo(viz::ResourceFormat format) { + GLFormatInfo info = { + true, + viz::GLInternalFormat(format), + viz::GLDataFormat(format), + viz::GLDataType(format), + }; + + if (info.internal_format == GL_ZERO || info.format == GL_ZERO || + info.type == GL_ZERO) { + return {false, GL_ZERO, GL_ZERO, GL_ZERO}; + } + + switch (format) { + case viz::BGRA_8888: + info.format = GL_RGBA; + info.internal_format = GL_RGBA; + break; + + // Technically we should use GL_RGB but CGLTexImageIOSurface2D() (and + // OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores + // the alpha channel anyway), see https://crbug.com/797347. + case viz::BGRX_1010102: + info.format = GL_RGBA; + info.internal_format = GL_RGBA; + break; + + default: + break; + } + + return info; +} + +void FlushIOSurfaceGLOperations() { + // The CGLTexImageIOSurface2D documentation says that we need to call + // glFlush, otherwise there is the risk of a race between different + // graphics contexts. + gl::GLApi* api = gl::g_current_gl_context; + api->glFlushFn(); +} + +} // anonymous namespace + +// Representation of a SharedImageBackingIOSurface as a GL Texture. +class SharedImageRepresentationGLTextureIOSurface + : public SharedImageRepresentationGLTexture { + public: + SharedImageRepresentationGLTextureIOSurface(SharedImageManager* manager, + SharedImageBacking* backing, + MemoryTypeTracker* tracker, + gles2::Texture* texture) + : SharedImageRepresentationGLTexture(manager, backing, tracker), + texture_(texture) { + DCHECK(texture_); + } + + ~SharedImageRepresentationGLTextureIOSurface() override { + texture_->RemoveLightweightRef(has_context()); + } + + gles2::Texture* GetTexture() override { return texture_; } + + bool BeginAccess(GLenum mode) override { return true; } + + void EndAccess() override { FlushIOSurfaceGLOperations(); } + + private: + gles2::Texture* texture_; + + DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureIOSurface); +}; + +// Representation of a SharedImageBackingIOSurface as a Skia Texture. +class SharedImageRepresentationSkiaIOSurface + : public SharedImageRepresentationSkia { + public: + SharedImageRepresentationSkiaIOSurface( + SharedImageManager* manager, + SharedImageBacking* backing, + sk_sp<SkPromiseImageTexture> promise_texture, + MemoryTypeTracker* tracker, + gles2::Texture* texture) + : SharedImageRepresentationSkia(manager, backing, tracker), + promise_texture_(std::move(promise_texture)), + texture_(texture) { + DCHECK(texture_); + DCHECK(promise_texture_); + } + + ~SharedImageRepresentationSkiaIOSurface() override { + texture_->RemoveLightweightRef(has_context()); + } + + sk_sp<SkSurface> BeginWriteAccess( + GrContext* gr_context, + int final_msaa_count, + const SkSurfaceProps& surface_props) override { + SkColorType sk_color_type = viz::ResourceFormatToClosestSkColorType( + /*gpu_compositing=*/true, format()); + + return SkSurface::MakeFromBackendTextureAsRenderTarget( + gr_context, promise_texture_->backendTexture(), + kTopLeft_GrSurfaceOrigin, final_msaa_count, sk_color_type, + backing()->color_space().ToSkColorSpace(), &surface_props); + } + + void EndWriteAccess(sk_sp<SkSurface> surface) override { + FlushIOSurfaceGLOperations(); + + if (texture_->IsLevelCleared(texture_->target(), 0)) { + backing()->SetCleared(); + } + } + + sk_sp<SkPromiseImageTexture> BeginReadAccess(SkSurface* sk_surface) override { + return promise_texture_; + } + + void EndReadAccess() override { FlushIOSurfaceGLOperations(); } + + private: + sk_sp<SkPromiseImageTexture> promise_texture_; + gles2::Texture* texture_; +}; + +// Implementation of SharedImageBacking by wrapping IOSurfaces +class SharedImageBackingIOSurface : public SharedImageBacking { + public: + SharedImageBackingIOSurface(const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage, + base::ScopedCFTypeRef<IOSurfaceRef> io_surface, + size_t estimated_size) + : SharedImageBacking(mailbox, + format, + size, + color_space, + usage, + estimated_size), + io_surface_(std::move(io_surface)) { + DCHECK(io_surface_); + } + ~SharedImageBackingIOSurface() final { DCHECK(!io_surface_); } + + bool IsCleared() const final { return is_cleared_; } + void SetCleared() final { + if (legacy_texture_) { + legacy_texture_->SetLevelCleared(legacy_texture_->target(), 0, true); + } + + is_cleared_ = true; + } + + void Update() final {} + + bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) final { + DCHECK(io_surface_); + + legacy_texture_ = GenGLTexture(); + if (!legacy_texture_) { + return false; + } + + mailbox_manager->ProduceTexture(mailbox(), legacy_texture_); + return true; + } + void Destroy() final { + DCHECK(io_surface_); + + if (legacy_texture_) { + legacy_texture_->RemoveLightweightRef(have_context()); + legacy_texture_ = nullptr; + } + + io_surface_.reset(); + } + + protected: + std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture( + SharedImageManager* manager, + MemoryTypeTracker* tracker) final { + gles2::Texture* texture = GenGLTexture(); + if (!texture) { + return nullptr; + } + + return std::make_unique<SharedImageRepresentationGLTextureIOSurface>( + manager, this, tracker, texture); + } + + std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia( + SharedImageManager* manager, + MemoryTypeTracker* tracker) override { + gles2::Texture* texture = GenGLTexture(); + if (!texture) { + return nullptr; + } + + GrBackendTexture backend_texture; + GetGrBackendTexture(gl::GLContext::GetCurrent()->GetVersionInfo(), + texture->target(), size(), texture->service_id(), + format(), &backend_texture); + sk_sp<SkPromiseImageTexture> promise_texture = + SkPromiseImageTexture::Make(backend_texture); + return std::make_unique<SharedImageRepresentationSkiaIOSurface>( + manager, this, promise_texture, tracker, texture); + } + + private: + gles2::Texture* GenGLTexture() { + GLFormatInfo gl_info = GetGLFormatInfo(format()); + DCHECK(gl_info.supported); + + // Wrap the IOSurface in a GLImageIOSurface + scoped_refptr<gl::GLImageIOSurface> image( + gl::GLImageIOSurface::Create(size(), gl_info.internal_format)); + if (!image->Initialize(io_surface_, gfx::GenericSharedMemoryId(), + viz::BufferFormat(format()))) { + LOG(ERROR) << "Failed to create GLImageIOSurface"; + return nullptr; + } + + gl::GLApi* api = gl::g_current_gl_context; + + // Save the currently bound rectangle texture to reset it once we are done. + GLint old_texture_binding = 0; + api->glGetIntegervFn(GL_TEXTURE_BINDING_RECTANGLE, &old_texture_binding); + + // Create a gles2 rectangle texture to bind to the IOSurface. + GLuint service_id = 0; + api->glGenTexturesFn(1, &service_id); + api->glBindTextureFn(GL_TEXTURE_RECTANGLE, service_id); + api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + // Bind the GLImageIOSurface to our texture + if (!image->BindTexImage(GL_TEXTURE_RECTANGLE)) { + LOG(ERROR) << "Failed to bind GLImageIOSurface"; + api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding); + api->glDeleteTexturesFn(1, &service_id); + return nullptr; + } + + // If the backing is already cleared, no need to clear it again. + gfx::Rect cleared_rect; + if (is_cleared_) { + cleared_rect = gfx::Rect(size()); + } + + // Manually create a gles2::Texture wrapping our driver texture. + gles2::Texture* texture = new gles2::Texture(service_id); + texture->SetLightweightRef(); + texture->SetTarget(GL_TEXTURE_RECTANGLE, 1); + texture->sampler_state_.min_filter = GL_LINEAR; + texture->sampler_state_.mag_filter = GL_LINEAR; + texture->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE; + texture->sampler_state_.wrap_s = GL_CLAMP_TO_EDGE; + texture->SetLevelInfo(GL_TEXTURE_RECTANGLE, 0, gl_info.internal_format, + size().width(), size().height(), 1, 0, gl_info.format, + gl_info.type, cleared_rect); + texture->SetLevelImage(GL_TEXTURE_RECTANGLE, 0, image.get(), + gles2::Texture::BOUND); + texture->SetImmutable(true); + + DCHECK_EQ(image->GetInternalFormat(), gl_info.format); + + api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding); + return texture; + } + + base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; + bool is_cleared_ = false; + + // A texture for the associated legacy mailbox. + gles2::Texture* legacy_texture_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(SharedImageBackingIOSurface); +}; + +// Implementation of SharedImageBackingFactoryIOSurface that creates +// SharedImageBackings wrapping IOSurfaces. +SharedImageBackingFactoryIOSurface::SharedImageBackingFactoryIOSurface( + const GpuDriverBugWorkarounds& workarounds, + const GpuFeatureInfo& gpu_feature_info) { + scoped_refptr<gles2::FeatureInfo> feature_info = + new gles2::FeatureInfo(workarounds, gpu_feature_info); + feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, false, + gles2::DisallowedFeatures()); + const gles2::Validators* validators = feature_info->validators(); + + // Precompute for each format if we can use it with GL. + for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) { + viz::ResourceFormat format = static_cast<viz::ResourceFormat>(i); + GLFormatInfo gl_info = GetGLFormatInfo(format); + + format_supported_by_gl_[i] = + gl_info.supported && + validators->texture_internal_format.IsValid(gl_info.internal_format) && + validators->texture_format.IsValid(gl_info.format) && + validators->pixel_type.IsValid(gl_info.type); + } +} + +SharedImageBackingFactoryIOSurface::~SharedImageBackingFactoryIOSurface() = + default; + +std::unique_ptr<SharedImageBacking> +SharedImageBackingFactoryIOSurface::CreateSharedImage( + const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage) { + // Check the format is supported and for simplicity always require it to be + // supported for GL. + if (!format_supported_by_gl_[format]) { + LOG(ERROR) << "viz::ResourceFormat " << format + << " not supported by IOSurfaces"; + return nullptr; + } + + // Calculate SharedImage size in bytes. + size_t estimated_size; + if (!viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size)) { + LOG(ERROR) << "Failed to calculate SharedImage size"; + return nullptr; + } + + base::ScopedCFTypeRef<IOSurfaceRef> io_surface( + gfx::CreateIOSurface(size, viz::BufferFormat(format), false)); + if (!io_surface) { + LOG(ERROR) << "Failed to allocate IOSurface."; + return nullptr; + } + + gfx::IOSurfaceSetColorSpace(io_surface, color_space); + + return std::make_unique<SharedImageBackingIOSurface>( + mailbox, format, size, color_space, usage, std::move(io_surface), + estimated_size); +} + +std::unique_ptr<SharedImageBacking> +SharedImageBackingFactoryIOSurface::CreateSharedImage( + const Mailbox& mailbox, + viz::ResourceFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage, + base::span<const uint8_t> pixel_data) { + NOTIMPLEMENTED(); + return nullptr; +} +std::unique_ptr<SharedImageBacking> +SharedImageBackingFactoryIOSurface::CreateSharedImage( + const Mailbox& mailbox, + int client_id, + gfx::GpuMemoryBufferHandle handle, + gfx::BufferFormat format, + SurfaceHandle surface_handle, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + uint32_t usage) { + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc new file mode 100644 index 0000000..aeb672a --- /dev/null +++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
@@ -0,0 +1,237 @@ +// Copyright 2019 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 "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h" + +#include <memory> +#include <utility> + +#include "base/bind_helpers.h" +#include "gpu/command_buffer/common/shared_image_usage.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" +#include "gpu/command_buffer/service/shared_context_state.h" +#include "gpu/command_buffer/service/shared_image_factory.h" +#include "gpu/command_buffer/service/shared_image_manager.h" +#include "gpu/command_buffer/service/shared_image_representation.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" +#include "gpu/config/gpu_feature_info.h" +#include "gpu/config/gpu_preferences.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkPromiseImageTexture.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/init/gl_factory.h" + +namespace gpu { +namespace { + +class SharedImageBackingFactoryIOSurfaceTest : public testing::Test { + public: + void SetUp() override { + surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); + ASSERT_TRUE(surface_); + context_ = gl::init::CreateGLContext(nullptr, surface_.get(), + gl::GLContextAttribs()); + ASSERT_TRUE(context_); + bool result = context_->MakeCurrent(surface_.get()); + ASSERT_TRUE(result); + + GpuDriverBugWorkarounds workarounds; + scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup(); + context_state_ = base::MakeRefCounted<SharedContextState>( + std::move(share_group), surface_, context_, + false /* use_virtualized_gl_contexts */, base::DoNothing()); + context_state_->InitializeGrContext(workarounds, nullptr); + auto feature_info = + base::MakeRefCounted<gles2::FeatureInfo>(workarounds, GpuFeatureInfo()); + context_state_->InitializeGL(GpuPreferences(), std::move(feature_info)); + + backing_factory_ = std::make_unique<SharedImageBackingFactoryIOSurface>( + workarounds, GpuFeatureInfo()); + + memory_type_tracker_ = std::make_unique<MemoryTypeTracker>(nullptr); + shared_image_representation_factory_ = + std::make_unique<SharedImageRepresentationFactory>( + &shared_image_manager_, nullptr); + } + + GrContext* gr_context() { return context_state_->gr_context(); } + + protected: + scoped_refptr<gl::GLSurface> surface_; + scoped_refptr<gl::GLContext> context_; + scoped_refptr<SharedContextState> context_state_; + std::unique_ptr<SharedImageBackingFactoryIOSurface> backing_factory_; + gles2::MailboxManagerImpl mailbox_manager_; + SharedImageManager shared_image_manager_; + std::unique_ptr<MemoryTypeTracker> memory_type_tracker_; + std::unique_ptr<SharedImageRepresentationFactory> + shared_image_representation_factory_; +}; + +// Basic test to check creation and deletion of IOSurface backed shared image. +TEST_F(SharedImageBackingFactoryIOSurfaceTest, Basic) { + Mailbox mailbox = Mailbox::GenerateForSharedImage(); + viz::ResourceFormat format = viz::ResourceFormat::RGBA_8888; + gfx::Size size(256, 256); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY; + + auto backing = backing_factory_->CreateSharedImage(mailbox, format, size, + color_space, usage); + EXPECT_TRUE(backing); + + // Check clearing. + if (!backing->IsCleared()) { + backing->SetCleared(); + EXPECT_TRUE(backing->IsCleared()); + } + + // First, validate via a legacy mailbox. + GLenum expected_target = GL_TEXTURE_RECTANGLE; + EXPECT_TRUE(backing->ProduceLegacyMailbox(&mailbox_manager_)); + TextureBase* texture_base = mailbox_manager_.ConsumeTexture(mailbox); + + // Currently there is no support for passthrough texture on Mac and hence + // in IOSurface backing. So the TextureBase* should be pointing to a Texture + // object. + auto* texture = gles2::Texture::CheckedCast(texture_base); + ASSERT_TRUE(texture); + EXPECT_EQ(texture->target(), expected_target); + EXPECT_TRUE(texture->IsImmutable()); + int width, height, depth; + bool has_level = + texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, &depth); + EXPECT_TRUE(has_level); + EXPECT_EQ(width, size.width()); + EXPECT_EQ(height, size.height()); + + // Next validate via a SharedImageRepresentationGLTexture. + std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref = + shared_image_manager_.Register(std::move(backing), + memory_type_tracker_.get()); + auto gl_representation = + shared_image_representation_factory_->ProduceGLTexture(mailbox); + EXPECT_TRUE(gl_representation); + EXPECT_TRUE(gl_representation->GetTexture()->service_id()); + EXPECT_EQ(expected_target, gl_representation->GetTexture()->target()); + EXPECT_EQ(size, gl_representation->size()); + EXPECT_EQ(format, gl_representation->format()); + EXPECT_EQ(color_space, gl_representation->color_space()); + EXPECT_EQ(usage, gl_representation->usage()); + gl_representation.reset(); + + // Finally, validate a SharedImageRepresentationSkia. + auto skia_representation = + shared_image_representation_factory_->ProduceSkia(mailbox); + EXPECT_TRUE(skia_representation); + auto surface = skia_representation->BeginWriteAccess( + gr_context(), 0, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); + EXPECT_TRUE(surface); + EXPECT_EQ(size.width(), surface->width()); + EXPECT_EQ(size.height(), surface->height()); + skia_representation->EndWriteAccess(std::move(surface)); + auto promise_texture = skia_representation->BeginReadAccess(nullptr); + EXPECT_TRUE(promise_texture); + if (promise_texture) { + GrBackendTexture backend_texture = promise_texture->backendTexture(); + EXPECT_TRUE(backend_texture.isValid()); + EXPECT_EQ(size.width(), backend_texture.width()); + EXPECT_EQ(size.height(), backend_texture.height()); + } + skia_representation->EndReadAccess(); + skia_representation.reset(); + + factory_ref.reset(); + EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox)); +} + +// Test to check interaction between Gl and skia GL representations. +// We write to a GL texture using gl representation and then read from skia +// representation. +TEST_F(SharedImageBackingFactoryIOSurfaceTest, GLSkiaGL) { + // Create a backing using mailbox. + auto mailbox = Mailbox::GenerateForSharedImage(); + auto format = viz::ResourceFormat::RGBA_8888; + gfx::Size size(1, 1); + auto color_space = gfx::ColorSpace::CreateSRGB(); + uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY; + auto backing = backing_factory_->CreateSharedImage(mailbox, format, size, + color_space, usage); + EXPECT_TRUE(backing); + + GLenum expected_target = GL_TEXTURE_RECTANGLE; + std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref = + shared_image_manager_.Register(std::move(backing), + memory_type_tracker_.get()); + + // Create a SharedImageRepresentationGLTexture. + auto gl_representation = + shared_image_representation_factory_->ProduceGLTexture(mailbox); + EXPECT_TRUE(gl_representation); + EXPECT_EQ(expected_target, gl_representation->GetTexture()->target()); + + // Create an FBO. + GLuint fbo = 0; + gl::GLApi* api = gl::g_current_gl_context; + api->glGenFramebuffersEXTFn(1, &fbo); + api->glBindFramebufferEXTFn(GL_FRAMEBUFFER, fbo); + + // Attach the texture to FBO. + api->glFramebufferTexture2DEXTFn( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + gl_representation->GetTexture()->target(), + gl_representation->GetTexture()->service_id(), 0); + + // Set the clear color to green. + api->glClearColorFn(0.0f, 1.0f, 0.0f, 1.0f); + api->glClearFn(GL_COLOR_BUFFER_BIT); + gl_representation.reset(); + + // Next create a SharedImageRepresentationSkia to read back the texture data. + auto skia_representation = + shared_image_representation_factory_->ProduceSkia(mailbox); + EXPECT_TRUE(skia_representation); + auto promise_texture = skia_representation->BeginReadAccess(nullptr); + EXPECT_TRUE(promise_texture); + if (promise_texture) { + GrBackendTexture backend_texture = promise_texture->backendTexture(); + EXPECT_TRUE(backend_texture.isValid()); + EXPECT_EQ(size.width(), backend_texture.width()); + EXPECT_EQ(size.height(), backend_texture.height()); + } + + // Create an Sk Image from GrBackendTexture. + auto sk_image = SkImage::MakeFromTexture( + gr_context(), promise_texture->backendTexture(), kTopLeft_GrSurfaceOrigin, + kRGBA_8888_SkColorType, kOpaque_SkAlphaType, nullptr); + + SkImageInfo dst_info = + SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType, + kOpaque_SkAlphaType, nullptr); + + const int num_pixels = size.width() * size.height(); + std::unique_ptr<uint8_t[]> dst_pixels(new uint8_t[num_pixels * 4]()); + + // Read back pixels from Sk Image. + EXPECT_TRUE(sk_image->readPixels(dst_info, dst_pixels.get(), + dst_info.minRowBytes(), 0, 0)); + skia_representation->EndReadAccess(); + + // Compare the pixel values. + EXPECT_EQ(dst_pixels[0], 0); + EXPECT_EQ(dst_pixels[1], 255); + EXPECT_EQ(dst_pixels[2], 0); + EXPECT_EQ(dst_pixels[3], 255); + + skia_representation.reset(); + factory_ref.reset(); + EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox)); +} + +} // anonymous namespace +} // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc index 8605158..c53291a 100644 --- a/gpu/command_buffer/service/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -30,6 +30,8 @@ #include "gpu/command_buffer/service/external_vk_image_factory.h" #elif defined(OS_ANDROID) && BUILDFLAG(ENABLE_VULKAN) #include "gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h" +#elif defined(OS_MACOSX) +#include "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h" #endif namespace gpu { @@ -77,6 +79,11 @@ std::make_unique<SharedImageBackingFactoryAHB>(workarounds, gpu_feature_info, context_state)), +#elif defined(OS_MACOSX) + interop_backing_factory_( + std::make_unique<SharedImageBackingFactoryIOSurface>( + workarounds, + gpu_feature_info)), #endif wrapped_sk_image_factory_( gpu_preferences.enable_raster_to_sk_image
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 993270b..1f66199e 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h
@@ -43,6 +43,9 @@ class SharedImageRepresentationGLTexture; class SharedImageRepresentationGLTextureAHB; class SharedImageRepresentationSkiaGLAHB; +class SharedImageBackingIOSurface; +class SharedImageRepresentationGLTextureIOSurface; +class SharedImageRepresentationSkiaIOSurface; namespace gles2 { class GLStreamTextureImage; @@ -375,6 +378,9 @@ friend class gpu::SharedImageBackingAHB; friend class gpu::SharedImageRepresentationGLTextureAHB; friend class gpu::SharedImageRepresentationSkiaGLAHB; + friend class gpu::SharedImageBackingIOSurface; + friend class gpu::SharedImageRepresentationGLTextureIOSurface; + friend class gpu::SharedImageRepresentationSkiaIOSurface; friend class TextureDefinition; friend class TextureManager; friend class TextureRef;
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index e96ecfc4..fea08b2 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -9,6 +9,11 @@ "type": "android" }, "gl_vendor": "Imagination.*", + "gl_type": "gles", + "gl_version": { + "op": "<", + "value": "3.0" + }, "features": [ "use_client_side_arrays_for_stream_buffers" ] @@ -21,6 +26,11 @@ "type": "android" }, "gl_vendor": "ARM.*", + "gl_type": "gles", + "gl_version": { + "op": "<", + "value": "3.0" + }, "features": [ "use_client_side_arrays_for_stream_buffers" ] @@ -3207,6 +3217,18 @@ "features": [ "rely_on_implicit_sync_for_swap_buffers" ] + }, + { + "id": 297, + "cr_bugs": [938678], + "description": "Needed to pass dEQP-EGL.functional.robustness.reset_context.shaders.infinite_loop.*", + "os": { + "type" : "chromeos" + }, + "vendor_id": "0x1002", + "features": [ + "exit_on_context_lost" + ] } ] }
diff --git a/gpu/config/gpu_driver_bug_list_unittest.cc b/gpu/config/gpu_driver_bug_list_unittest.cc index 88646b3..58739a41 100644 --- a/gpu/config/gpu_driver_bug_list_unittest.cc +++ b/gpu/config/gpu_driver_bug_list_unittest.cc
@@ -24,6 +24,7 @@ GPUInfo gpu_info; gpu_info.gl_vendor = "ARM"; gpu_info.gl_renderer = "MALi_T604"; + gpu_info.gl_version = "OpenGL ES 2.0"; std::set<int> bugs = list->MakeDecision( GpuControlList::kOsAndroid, "4.1", gpu_info); EXPECT_EQ(1u, bugs.count(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS)); @@ -34,6 +35,7 @@ GPUInfo gpu_info; gpu_info.gl_vendor = "Imagination Technologies"; gpu_info.gl_renderer = "PowerVR SGX 540"; + gpu_info.gl_version = "OpenGL ES 2.0"; std::set<int> bugs = list->MakeDecision( GpuControlList::kOsAndroid, "4.1", gpu_info); EXPECT_EQ(1u, bugs.count(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS));
diff --git a/gpu/ipc/client/DEPS b/gpu/ipc/client/DEPS index 3333b39..7a79c6ac 100644 --- a/gpu/ipc/client/DEPS +++ b/gpu/ipc/client/DEPS
@@ -14,7 +14,6 @@ "+media/filters/jpeg_parser.h", ], "raster_in_process_context_tests.cc": [ - "+cc/paint/color_space_transfer_cache_entry.h", "+components/viz/common/resources/resource_format.h", "+components/viz/common/resources/resource_format_utils.h", "+components/viz/test/test_gpu_memory_buffer_manager.h",
diff --git a/gpu/ipc/client/raster_in_process_context_tests.cc b/gpu/ipc/client/raster_in_process_context_tests.cc index 9d357d4..520066d 100644 --- a/gpu/ipc/client/raster_in_process_context_tests.cc +++ b/gpu/ipc/client/raster_in_process_context_tests.cc
@@ -5,7 +5,6 @@ #include <memory> #include "build/build_config.h" -#include "cc/paint/color_space_transfer_cache_entry.h" #include "components/viz/common/resources/resource_format.h" #include "components/viz/test/test_gpu_memory_buffer_manager.h" #include "gpu/command_buffer/client/raster_implementation.h"
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 84f1854f..1daa26e 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -1844,10 +1844,6 @@ mixins: "win-gpu-fyi-ci" } builders { - name: "GPU FYI Win Clang Builder (dbg)" - mixins: "win-gpu-fyi-ci" - } - builders { name: "GPU FYI Win dEQP Builder" mixins: "win-gpu-fyi-ci" }
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index fa1894b..ffdc316f 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg
@@ -3051,11 +3051,6 @@ short_name: "x64" } builders { - name: "buildbucket/luci.chromium.ci/GPU FYI Win Clang Builder (dbg)" - category: "Windows|Builder|Debug" - short_name: "clg" - } - builders { name: "buildbucket/luci.chromium.ci/Win10 FYI Debug (NVIDIA)" category: "Windows|10|Nvidia" short_name: "dbg"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg index 87ffee2..d25de57 100644 --- a/infra/config/luci-scheduler.cfg +++ b/infra/config/luci-scheduler.cfg
@@ -152,7 +152,6 @@ triggers: "GPU FYI Mac dEQP Builder" triggers: "GPU FYI Win Builder (dbg)" triggers: "GPU FYI Win Builder" - triggers: "GPU FYI Win Clang Builder (dbg)" triggers: "GPU FYI Win dEQP Builder" triggers: "GPU FYI Win x64 Builder (dbg)" triggers: "GPU FYI Win x64 Builder" @@ -2543,16 +2542,6 @@ } job { - id: "GPU FYI Win Clang Builder (dbg)" - acl_sets: "default" - buildbucket: { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "GPU FYI Win Clang Builder (dbg)" - } -} - -job { id: "GPU FYI Win dEQP Builder" acl_sets: "default" buildbucket: {
diff --git a/ios/build/bots/chromium.mac/ios-slimnav.json b/ios/build/bots/chromium.mac/ios-slimnav.json index 94827d46..3c55bc9 100644 --- a/ios/build/bots/chromium.mac/ios-slimnav.json +++ b/ios/build/bots/chromium.mac/ios-slimnav.json
@@ -17,7 +17,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s Plus", "os": "12.1", @@ -28,7 +28,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s", "os": "12.1", @@ -39,7 +39,7 @@ { "include": "common_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s", "os": "12.1", @@ -50,7 +50,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -61,7 +61,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s Plus", "os": "11.4", @@ -72,7 +72,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s", "os": "11.4", @@ -83,7 +83,7 @@ { "include": "common_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s", "os": "11.4", @@ -94,7 +94,7 @@ { "include": "screen_size_dependent_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -105,7 +105,7 @@ { "include": "eg_cq_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone 6s", "os": "11.4", @@ -116,7 +116,7 @@ { "app": "ios_chrome_bookmarks_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -129,7 +129,7 @@ { "app": "ios_chrome_manual_fill_egtests", "test args": [ - "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager" + "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -141,7 +141,7 @@ { "app": "ios_chrome_web_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -153,7 +153,7 @@ { "app": "ios_chrome_settings_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -165,7 +165,7 @@ { "app": "ios_chrome_reading_list_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -177,7 +177,7 @@ { "app": "ios_showcase_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -189,7 +189,7 @@ { "app": "ios_chrome_bookmarks_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "shard size": 2, "device type": "iPad Air 2", @@ -202,7 +202,7 @@ { "app": "ios_chrome_manual_fill_egtests", "test args": [ - "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager" + "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManagerr,OfflineVersionWithoutNativeContent" ], "xctest": true, "device type": "iPad Air 2", @@ -214,7 +214,7 @@ { "app": "ios_chrome_web_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -226,7 +226,7 @@ { "app": "ios_chrome_settings_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -238,7 +238,7 @@ { "app": "ios_chrome_reading_list_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -250,7 +250,7 @@ { "app": "ios_showcase_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -262,7 +262,7 @@ { "app": "ios_chrome_bookmarks_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -275,7 +275,7 @@ { "app": "ios_chrome_manual_fill_egtests", "test args": [ - "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager" + "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManagerr,OfflineVersionWithoutNativeContent" ], "xctest": true, "device type": "iPhone X", @@ -287,7 +287,7 @@ { "app": "ios_chrome_web_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -299,7 +299,7 @@ { "app": "ios_chrome_settings_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -311,7 +311,7 @@ { "app": "ios_chrome_reading_list_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -323,7 +323,7 @@ { "app": "ios_showcase_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -335,7 +335,7 @@ { "app": "ios_chrome_bookmarks_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "shard size": 2, "device type": "iPhone X", @@ -348,7 +348,7 @@ { "app": "ios_chrome_manual_fill_egtests", "test args": [ - "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager" + "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManagerr,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1", @@ -360,7 +360,7 @@ { "app": "ios_chrome_web_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1", @@ -372,7 +372,7 @@ { "app": "ios_chrome_settings_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1", @@ -384,7 +384,7 @@ { "app": "ios_chrome_reading_list_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1", @@ -396,7 +396,7 @@ { "app": "ios_showcase_egtests", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1", @@ -408,7 +408,7 @@ { "include": "eg_cq_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -419,7 +419,7 @@ { "include": "eg_cq_tests.json", "test args": [ - "--enable-features=SlimNavigationManager" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index 56a37c9..4217b33 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -313,6 +313,12 @@ {"autofill-dynamic-forms", flag_descriptions::kAutofillDynamicFormsName, flag_descriptions::kAutofillDynamicFormsDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(autofill::features::kAutofillDynamicForms)}, + {"autofill-no-local-save-on-upload-success", + flag_descriptions::kAutofillNoLocalSaveOnUploadSuccessName, + flag_descriptions::kAutofillNoLocalSaveOnUploadSuccessDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE( + autofill::features::kAutofillNoLocalSaveOnUploadSuccess)}, {"autofill-prefilled-fields", flag_descriptions::kAutofillPrefilledFieldsName, flag_descriptions::kAutofillPrefilledFieldsDescription, flags_ui::kOsIos,
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index d9d3d6ea..46e5205c 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -142,6 +142,13 @@ const char kAutofillDynamicFormsDescription[] = "Refills forms that dynamically change after an initial fill"; +const char kAutofillNoLocalSaveOnUploadSuccessName[] = + "Disable saving local copy of uploaded card when credit card upload " + "succeeds"; +const char kAutofillNoLocalSaveOnUploadSuccessDescription[] = + "When enabled, no local copy of server card will be saved when credit card " + "upload succeeds."; + const char kAutofillPrefilledFieldsName[] = "Autofill prefilled forms"; const char kAutofillPrefilledFieldsDescription[] = "Fills forms that contain a programmatically filled value.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index 00a2007c..1d28b4a 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -111,6 +111,11 @@ extern const char kAutofillDynamicFormsName[]; extern const char kAutofillDynamicFormsDescription[]; +// Title and description for the flag to control saving FULL_SERVER_CARDS upon +// success of credit card upload. +extern const char kAutofillNoLocalSaveOnUploadSuccessName[]; +extern const char kAutofillNoLocalSaveOnUploadSuccessDescription[]; + // Title and description for the flag to control the dynamic autofill. extern const char kAutofillPrefilledFieldsName[]; extern const char kAutofillPrefilledFieldsDescription[];
diff --git a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm index 4a511b2..148f2cf28 100644 --- a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm +++ b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
@@ -144,10 +144,6 @@ return; } offline_navigation_triggered_ = GURL::EmptyGURL(); - if (!reading_list_model_->loaded()) { - initial_navigation_url_ = GURL::EmptyGURL(); - return; - } initial_navigation_url_ = context->GetUrl(); loading_slow_or_failed_ = false; navigation_committed_ = false; @@ -194,7 +190,9 @@ PresentOfflinePageForOnlineUrl(url); return; } - if (!url.is_valid() || !reading_list_model_->GetEntryByURL(url)) { + + if (!url.is_valid() || !reading_list_model_->loaded() || + !reading_list_model_->GetEntryByURL(url)) { return; } reading_list_model_->SetReadStatus(url, true); @@ -209,8 +207,9 @@ void OfflinePageTabHelper::ReadingListModelLoaded( const ReadingListModel* model) { - // There is no need to do anything. If the navigation is in progress then - // CheckLoadingProgress might still present distilled version of the page. + if (navigation_committed_ && loading_slow_or_failed_) { + PresentOfflinePageForOnlineUrl(initial_navigation_url_); + } } void OfflinePageTabHelper::ReadingListModelBeingDeleted(
diff --git a/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm b/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm index a4070f7..2cefd46a 100644 --- a/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm +++ b/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm
@@ -28,19 +28,130 @@ const char kTestDistilledPath[] = "distilled.html"; const char kTestDistilledURL[] = "http://foo.bar/distilled"; const char kTestDirectory[] = "ios/testing/data/"; + +// A simple implementation of ReadingListModel that only support functions +// needed to load an offline page. +class FakeReadingListModel : public ReadingListModel { + public: + ~FakeReadingListModel() override {} + bool loaded() const override { return loaded_; } + + syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override { + NOTREACHED(); + return nullptr; + } + + const std::vector<GURL> Keys() const override { + NOTREACHED(); + return std::vector<GURL>(); + } + + size_t size() const override { + DCHECK(loaded_); + return 0; + } + + size_t unread_size() const override { + NOTREACHED(); + return 0; + } + + size_t unseen_size() const override { + NOTREACHED(); + return 0; + } + + void MarkAllSeen() override { NOTREACHED(); } + + bool DeleteAllEntries() override { + NOTREACHED(); + return false; + } + + bool GetLocalUnseenFlag() const override { + NOTREACHED(); + return false; + } + + void ResetLocalUnseenFlag() override { NOTREACHED(); } + + const ReadingListEntry* GetEntryByURL(const GURL& gurl) const override { + DCHECK(loaded_); + if (entry_->URL() == gurl) { + return entry_; + } + return nullptr; + } + + const ReadingListEntry* GetFirstUnreadEntry(bool distilled) const override { + NOTREACHED(); + return nullptr; + } + + const ReadingListEntry& AddEntry(const GURL& url, + const std::string& title, + reading_list::EntrySource source) override { + NOTREACHED(); + return *entry_; + } + + void RemoveEntryByURL(const GURL& url) override { NOTREACHED(); } + + void SetReadStatus(const GURL& url, bool read) override { + if (entry_->URL() == url) { + entry_->SetRead(true, base::Time()); + } + } + + void SetEntryTitle(const GURL& url, const std::string& title) override { + NOTREACHED(); + } + + void SetEntryDistilledState( + const GURL& url, + ReadingListEntry::DistillationState state) override { + NOTREACHED(); + } + + void SetEntryDistilledInfo(const GURL& url, + const base::FilePath& distilled_path, + const GURL& distilled_url, + int64_t distilation_size, + const base::Time& distilation_time) override { + NOTREACHED(); + } + + void SetContentSuggestionsExtra( + const GURL& url, + const reading_list::ContentSuggestionsExtra& extra) override { + NOTREACHED(); + } + + void SetEntry(ReadingListEntry* entry) { entry_ = entry; } + void SetLoaded() { + loaded_ = true; + for (auto& observer : observers_) { + observer.ReadingListModelLoaded(this); + } + } + + private: + ReadingListEntry* entry_ = nullptr; + bool loaded_ = false; +}; } // Test fixture to test loading of Reading list offline pages. class OfflinePageTabHelperTest : public web::WebTest { public: void SetUp() override { + web::WebTest::SetUp(); TestChromeBrowserState::Builder test_cbs_builder; base::FilePath test_data_dir; ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); test_data_dir = test_data_dir.AppendASCII(kTestDirectory); test_cbs_builder.SetPath(test_data_dir); chrome_browser_state_ = test_cbs_builder.Build(); - test_web_state_.SetBrowserState(chrome_browser_state_.get()); reading_list_model_ = std::make_unique<ReadingListModelImpl>( /*storage_layer*/ nullptr, /*pref_service*/ nullptr, @@ -57,6 +168,37 @@ web::TestWebState test_web_state_; }; +// Test fixture to test loading of Reading list offline pages with a delayed +// ReadingListModel. +class OfflinePageTabHelperDelayedModelTest : public web::WebTest { + void SetUp() override { + web::WebTest::SetUp(); + TestChromeBrowserState::Builder test_cbs_builder; + base::FilePath test_data_dir; + ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); + test_data_dir = test_data_dir.AppendASCII(kTestDirectory); + test_cbs_builder.SetPath(test_data_dir); + chrome_browser_state_ = test_cbs_builder.Build(); + test_web_state_.SetBrowserState(chrome_browser_state_.get()); + fake_reading_list_model_ = std::make_unique<FakeReadingListModel>(); + GURL url(kTestURL); + entry_ = std::make_unique<ReadingListEntry>(url, kTestTitle, base::Time()); + std::string distilled_path = kTestDistilledPath; + entry_->SetDistilledInfo(base::FilePath(distilled_path), + GURL(kTestDistilledURL), 50, + base::Time::FromTimeT(100)); + fake_reading_list_model_->SetEntry(entry_.get()); + OfflinePageTabHelper::CreateForWebState(&test_web_state_, + fake_reading_list_model_.get()); + } + + protected: + std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; + std::unique_ptr<FakeReadingListModel> fake_reading_list_model_; + web::TestWebState test_web_state_; + std::unique_ptr<ReadingListEntry> entry_; +}; + // Tests that loading an online version does mark it read. TEST_F(OfflinePageTabHelperTest, TestLoadReadingListSuccess) { GURL url(kTestURL); @@ -173,3 +315,34 @@ base::Time::FromTimeT(100)); EXPECT_TRUE(offline_page_tab_helper->HasDistilledVersionForOnlineUrl(url)); } + +// Tests that OfflinePageTabHelper correctly shows Offline page if model takes +// a long time to load. +TEST_F(OfflinePageTabHelperDelayedModelTest, TestLateReadingListModelLoading) { + OfflinePageTabHelper* offline_page_tab_helper = + OfflinePageTabHelper::FromWebState(&test_web_state_); + GURL url(kTestURL); + EXPECT_FALSE(offline_page_tab_helper->HasDistilledVersionForOnlineUrl(url)); + web::FakeNavigationContext context; + + context.SetHasCommitted(true); + context.SetUrl(url); + test_web_state_.OnNavigationStarted(&context); + test_web_state_.OnNavigationFinished(&context); + test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::FAILURE); + EXPECT_FALSE(base::test::ios::WaitUntilConditionOrTimeout( + base::test::ios::kWaitForFileOperationTimeout, ^bool { + base::RunLoop().RunUntilIdle(); + return test_web_state_.GetLastLoadedData(); + })); + EXPECT_FALSE(entry_->IsRead()); + EXPECT_FALSE(offline_page_tab_helper->presenting_offline_page()); + fake_reading_list_model_->SetLoaded(); + EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( + base::test::ios::kWaitForFileOperationTimeout, ^bool { + base::RunLoop().RunUntilIdle(); + return test_web_state_.GetLastLoadedData(); + })); + EXPECT_TRUE(entry_->IsRead()); + EXPECT_TRUE(offline_page_tab_helper->presenting_offline_page()); +}
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn index 7d87fab..af9142f 100644 --- a/ios/chrome/browser/signin/BUILD.gn +++ b/ios/chrome/browser/signin/BUILD.gn
@@ -123,6 +123,7 @@ deps = [ ":signin", "//base", + "//components/image_fetcher/core:test_support", "//components/keyed_service/core", "//components/signin/core/browser:internals_test_support", "//components/signin/ios/browser",
diff --git a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc index ab13af6..4c8cc81 100644 --- a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc +++ b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
@@ -8,7 +8,6 @@ #include "base/bind.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm index ee084d1..663d272 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -570,10 +570,6 @@ // appearing, and that the Reading List entry is present in the Reading List. // Loads online version by tapping on entry. - (void)testSavingToReadingListAndLoadNormal { - // TODO(crbug.com/874649): re-enable this test. - if (base::FeatureList::IsEnabled(web::features::kSlimNavigationManager)) - EARL_GREY_TEST_DISABLED(@"Test disabled on SlimNavigationManager."); - auto network_change_disabler = std::make_unique<net::NetworkChangeNotifier::DisableForTest>(); auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>(); @@ -611,14 +607,6 @@ // appearing, and that the Reading List entry is present in the Reading List. // Loads offline version by tapping on entry without web server. - (void)testSavingToReadingListAndLoadNoNetwork { - // TODO(crbug.com/874649): re-enable this test. - if (base::FeatureList::IsEnabled(web::features::kSlimNavigationManager)) - EARL_GREY_TEST_DISABLED(@"Test disabled on SlimNavigationManager."); - - // TODO(crbug.com/936773): re-enable this test. - if (reading_list::IsOfflinePageWithoutNativeContentEnabled()) - EARL_GREY_TEST_DISABLED(@"Test disabled on SlimNavigationManager."); - auto network_change_disabler = std::make_unique<net::NetworkChangeNotifier::DisableForTest>(); auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>(); @@ -666,14 +654,6 @@ // appearing, and that the Reading List entry is present in the Reading List. // Loads offline version by tapping on entry with delayed web server. - (void)testSavingToReadingListAndLoadBadNetwork { - // TODO(crbug.com/905839): re-enable this test. - if (base::FeatureList::IsEnabled(web::features::kSlimNavigationManager)) - EARL_GREY_TEST_DISABLED(@"Test disabled on SlimNavigationManager."); - - // TODO(crbug.com/936773): re-enable this test. - if (reading_list::IsOfflinePageWithoutNativeContentEnabled()) - EARL_GREY_TEST_DISABLED(@"Test disabled on SlimNavigationManager."); - auto network_change_disabler = std::make_unique<net::NetworkChangeNotifier::DisableForTest>(); auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>();
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm index 1897cbf..c41dfca 100644 --- a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
@@ -551,10 +551,14 @@ NSString* continueButtonTitle = l10n_util::GetNSString(IDS_IOS_DISCONNECT_DIALOG_CONTINUE_BUTTON_MOBILE); if ([self authService] -> IsAuthenticatedIdentityManaged()) { - std::string hosted_domain = - IdentityManagerFactory::GetForBrowserState(_browserState) - ->GetPrimaryAccountInfo() - .hosted_domain; + identity::IdentityManager* identityManager = + IdentityManagerFactory::GetForBrowserState(_browserState); + base::Optional<AccountInfo> accountInfo = + identityManager->FindExtendedAccountInfoForAccount( + identityManager->GetPrimaryAccountInfo()); + std::string hosted_domain = accountInfo.has_value() + ? accountInfo.value().hosted_domain + : std::string(); if (unified_consent::IsUnifiedConsentFeatureEnabled()) { title = l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE_UNITY);
diff --git a/ios/chrome/browser/ui/translate/translate_infobar_view.mm b/ios/chrome/browser/ui/translate/translate_infobar_view.mm index e06061b7a..461e80e3 100644 --- a/ios/chrome/browser/ui/translate/translate_infobar_view.mm +++ b/ios/chrome/browser/ui/translate/translate_infobar_view.mm
@@ -95,9 +95,16 @@ if (!self.superview) return; - [NamedGuide guideWithName:kTranslateInfobarOptionsGuide - view:self.optionsButton] - .constrainedView = self.optionsButton; + // Constrain the options button named guide to its corresponding view. Reset + // the named guide's existing constrained view beforehand. Otherwise this will + // be a no-op if the new constrained view is the same as the existing one, + // even though the existing constraints are invalid (e.g., when the infobar is + // removed from the view hierarchy and added again after a tab switch). + NamedGuide* namedGuide = + [NamedGuide guideWithName:kTranslateInfobarOptionsGuide + view:self.optionsButton]; + [namedGuide resetConstraints]; + namedGuide.constrainedView = self.optionsButton; // The initial bottom padding should be the current height of the secondary // toolbar or the bottom safe area inset, whichever is greater.
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index fffd472..35ab14e 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -51,11 +51,6 @@ public_deps = [ ":shared_helper_headers", ] - - include_dirs = [ - "//ios/third_party/earl_grey2/src", - "//ios/third_party/edo/src", - ] } group("eg_test_support+eg2") { @@ -76,8 +71,6 @@ "smoke_egtest.mm", ] - include_dirs = [ "//ios/third_party/edo/src" ] - deps = [ ":eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib",
diff --git a/ios/testing/DEPS b/ios/testing/DEPS index d9bd356..616b5038 100644 --- a/ios/testing/DEPS +++ b/ios/testing/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+ios/third_party/earl_grey2/src", "+net", "+third_party/google_toolbox_for_mac", "+third_party/ocmock",
diff --git a/ios/testing/earl_grey/BUILD.gn b/ios/testing/earl_grey/BUILD.gn index 86694a5a..1818cd25 100644 --- a/ios/testing/earl_grey/BUILD.gn +++ b/ios/testing/earl_grey/BUILD.gn
@@ -2,11 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -config("earl_grey_support_config") { - include_dirs = [ "." ] - visibility = [ ":earl_grey_support" ] -} - source_set("earl_grey_support") { defines = [ "CHROME_EARL_GREY_1" ] configs += [ "//build/config/compiler:enable_arc" ] @@ -19,12 +14,11 @@ sources = [ "disabled_test_macros.h", + "earl_grey_app.h", + "earl_grey_test.h", "matchers.h", "matchers.mm", ] - - public_configs = [ ":earl_grey_support_config" ] - configs += [ ":earl_grey_support_config" ] } source_set("eg_app_support+eg2") { @@ -38,12 +32,10 @@ ] sources = [ + "earl_grey_app.h", "matchers.h", "matchers.mm", ] - - public_configs = [ ":earl_grey_support_config" ] - configs += [ ":earl_grey_support_config" ] } source_set("eg_test_support+eg2") { @@ -52,5 +44,10 @@ sources = [ "disabled_test_macros.h", + "earl_grey_test.h", + ] + + deps = [ + "//ios/third_party/earl_grey2:test_lib", ] }
diff --git a/ios/testing/earl_grey/earl_grey_app.h b/ios/testing/earl_grey/earl_grey_app.h new file mode 100644 index 0000000..4f9facc --- /dev/null +++ b/ios/testing/earl_grey/earl_grey_app.h
@@ -0,0 +1,28 @@ +// Copyright 2019 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_TESTING_EARL_GREY_EARL_GREY_APP_H_ +#define IOS_TESTING_EARL_GREY_EARL_GREY_APP_H_ + +// Contains includes and typedefs to allow code to compile under both EarlGrey1 +// and EarlGrey2 (App Process). + +#if defined(CHROME_EARL_GREY_1) + +#import <EarlGrey/EarlGrey.h> + +typedef DescribeToBlock GREYDescribeToBlock; +typedef MatchesBlock GREYMatchesBlock; + +#elif defined(CHROME_EARL_GREY_2) + +#import <AppFramework/Action/GREYActionsShorthand.h> +#import <AppFramework/EarlGreyApp.h> +#import <AppFramework/Matcher/GREYMatchersShorthand.h> + +#else +#error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. +#endif + +#endif // IOS_TESTING_EARL_GREY_EARL_GREY_APP_H_
diff --git a/ios/testing/earl_grey/earl_grey_test.h b/ios/testing/earl_grey/earl_grey_test.h new file mode 100644 index 0000000..5255743c --- /dev/null +++ b/ios/testing/earl_grey/earl_grey_test.h
@@ -0,0 +1,26 @@ +// Copyright 2019 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_TESTING_EARL_GREY_EARL_GREY_TEST_H_ +#define IOS_TESTING_EARL_GREY_EARL_GREY_TEST_H_ + +// Contains includes and typedefs to allow code to compile under both EarlGrey1 +// and EarlGrey2 (Test Process). + +#if defined(CHROME_EARL_GREY_1) + +#import <EarlGrey/EarlGrey.h> + +typedef DescribeToBlock GREYDescribeToBlock; +typedef MatchesBlock GREYMatchesBlock; + +#elif defined(CHROME_EARL_GREY_2) + +#import "ios/third_party/earl_grey2/src/TestLib/EarlGreyImpl/EarlGrey.h" // nogncheck + +#else +#error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. +#endif + +#endif // IOS_TESTING_EARL_GREY_EARL_GREY_TEST_H_
diff --git a/ios/testing/earl_grey/matchers.mm b/ios/testing/earl_grey/matchers.mm index 7903f03..35c2c67 100644 --- a/ios/testing/earl_grey/matchers.mm +++ b/ios/testing/earl_grey/matchers.mm
@@ -3,20 +3,12 @@ // found in the LICENSE file. #import "ios/testing/earl_grey/matchers.h" +#include "ios/testing/earl_grey/earl_grey_app.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -#if defined(CHROME_EARL_GREY_1) -#import <EarlGrey/EarlGrey.h> -#endif - -#if defined(CHROME_EARL_GREY_2) -#import <AppFramework/EarlGreyApp.h> -#import <AppFramework/Matcher/GREYMatchersShorthand.h> -#endif - namespace testing { id<GREYMatcher> ButtonWithAccessibilityLabel(NSString* label) {
diff --git a/ios/third_party/earl_grey2/BUILD.gn b/ios/third_party/earl_grey2/BUILD.gn index 52aeeb6..551c92b 100644 --- a/ios/third_party/earl_grey2/BUILD.gn +++ b/ios/third_party/earl_grey2/BUILD.gn
@@ -6,7 +6,10 @@ import("//build/config/ios/rules.gni") config("config") { - include_dirs = [ "//ios/third_party/earl_grey2/src" ] + include_dirs = [ + "//ios/third_party/earl_grey2/src", + "//ios/third_party/edo/src", + ] } group("earl_grey2") {
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn index 1ed62261..85c03fb 100644 --- a/ios/third_party/material_components_ios/BUILD.gn +++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -297,27 +297,27 @@ "src/components/ShadowLayer/src/MDCShadowLayer.h", "src/components/ShadowLayer/src/MDCShadowLayer.m", "src/components/ShadowLayer/src/MaterialShadowLayer.h", + "src/components/ShapeLibrary/src/MDCCornerTreatment+CornerTypeInitalizer.h", "src/components/ShapeLibrary/src/MDCCornerTreatment+CornerTypeInitalizer.m", - "src/components/ShapeLibrary/src/MDCCornerTreatment+CornerTypeInitalizerNew.h", + "src/components/ShapeLibrary/src/MDCCurvedCornerTreatment.h", "src/components/ShapeLibrary/src/MDCCurvedCornerTreatment.m", - "src/components/ShapeLibrary/src/MDCCurvedCornerTreatmentNew.h", + "src/components/ShapeLibrary/src/MDCCutCornerTreatment.h", "src/components/ShapeLibrary/src/MDCCutCornerTreatment.m", - "src/components/ShapeLibrary/src/MDCCutCornerTreatmentNew.h", + "src/components/ShapeLibrary/src/MDCRoundedCornerTreatment.h", "src/components/ShapeLibrary/src/MDCRoundedCornerTreatment.m", - "src/components/ShapeLibrary/src/MDCRoundedCornerTreatmentNew.h", + "src/components/Shapes/src/MDCCornerTreatment.h", "src/components/Shapes/src/MDCCornerTreatment.m", - "src/components/Shapes/src/MDCCornerTreatmentNew.h", + "src/components/Shapes/src/MDCEdgeTreatment.h", "src/components/Shapes/src/MDCEdgeTreatment.m", - "src/components/Shapes/src/MDCEdgeTreatmentNew.h", + "src/components/Shapes/src/MDCPathGenerator.h", "src/components/Shapes/src/MDCPathGenerator.m", - "src/components/Shapes/src/MDCPathGeneratorNew.h", + "src/components/Shapes/src/MDCRectangleShapeGenerator.h", "src/components/Shapes/src/MDCRectangleShapeGenerator.m", - "src/components/Shapes/src/MDCRectangleShapeGeneratorNew.h", + "src/components/Shapes/src/MDCShapedShadowLayer.h", "src/components/Shapes/src/MDCShapedShadowLayer.m", - "src/components/Shapes/src/MDCShapedShadowLayerNew.h", + "src/components/Shapes/src/MDCShapedView.h", "src/components/Shapes/src/MDCShapedView.m", - "src/components/Shapes/src/MDCShapedViewNew.h", - "src/components/Shapes/src/MaterialShapesNew.h", + "src/components/Shapes/src/MaterialShapes.h", "src/components/Snackbar/src/MDCSnackbarManager.h", "src/components/Snackbar/src/MDCSnackbarManager.m", "src/components/Snackbar/src/MDCSnackbarMessage.h",
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm index 0b6fccdbe..a51f21c 100644 --- a/ios/web/navigation/legacy_navigation_manager_impl.mm +++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -158,15 +158,7 @@ } int LegacyNavigationManagerImpl::GetPendingItemIndex() const { - if (GetPendingItem()) { - if ([session_controller_ pendingItemIndex] != -1) { - return [session_controller_ pendingItemIndex]; - } - // TODO(crbug.com/665189): understand why last committed item index is - // returned here. - return GetLastCommittedItemIndex(); - } - return -1; + return [session_controller_ pendingItemIndex]; } int LegacyNavigationManagerImpl:: @@ -358,7 +350,7 @@ } void LegacyNavigationManagerImpl::SetPendingItemIndex(int index) { - NOTREACHED(); + session_controller_.pendingItemIndex = index; } } // namespace web
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm index ebc6f75..530d791 100644 --- a/ios/web/navigation/navigation_manager_impl_unittest.mm +++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -236,8 +236,7 @@ EXPECT_EQ(-1, navigation_manager()->GetPendingItemIndex()); } -// Tests that GetPendingItemIndex() returns current item index if there is a -// pending entry. +// Tests that GetPendingItemIndex() returns -1 if there is a pending item. TEST_P(NavigationManagerTest, GetPendingItemIndexWithPendingEntry) { navigation_manager()->AddPendingItem( GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED, @@ -251,6 +250,19 @@ GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED, web::NavigationInitiationType::BROWSER_INITIATED, web::NavigationManager::UserAgentOverrideOption::INHERIT); + EXPECT_EQ(-1, navigation_manager()->GetPendingItemIndex()); +} + +// Tests that setting and getting PendingItemIndex. +TEST_P(NavigationManagerTest, SetAndGetPendingItemIndex) { + navigation_manager()->AddPendingItem( + GURL("http://www.url.test"), Referrer(), ui::PAGE_TRANSITION_TYPED, + web::NavigationInitiationType::BROWSER_INITIATED, + web::NavigationManager::UserAgentOverrideOption::INHERIT); + [mock_wk_list_ setCurrentURL:@"http://www.url.test"]; + navigation_manager()->CommitPendingItem(); + + navigation_manager()->SetPendingItemIndex(0); EXPECT_EQ(0, navigation_manager()->GetPendingItemIndex()); }
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm index 3ab5ec5..c4f53648 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl.mm +++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -372,15 +372,9 @@ } int WKBasedNavigationManagerImpl::GetPendingItemIndex() const { - if (GetPendingItem()) { - if (pending_item_index_ != -1) { - return pending_item_index_; - } - // TODO(crbug.com/665189): understand why last committed item index is - // returned here. - return GetLastCommittedItemIndex(); - } - return -1; + if (is_restore_session_in_progress_) + return -1; + return pending_item_index_; } bool WKBasedNavigationManagerImpl::RemoveItemAtIndex(int index) {
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn index e05de3f..a52d68d 100644 --- a/ios/web/shell/test/BUILD.gn +++ b/ios/web/shell/test/BUILD.gn
@@ -124,8 +124,6 @@ "earl_grey/web_shell_test_case.mm", ] - include_dirs = [ "//ios/third_party/edo/src" ] - deps = [ "//ios/testing/earl_grey:eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib", @@ -144,8 +142,6 @@ "web_shell_sample_egtest.mm", ] - include_dirs = [ "//ios/third_party/edo/src" ] - deps = [ ":eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib",
diff --git a/ios/web/shell/test/earl_grey/web_shell_test_case.mm b/ios/web/shell/test/earl_grey/web_shell_test_case.mm index bf79531..8827aee 100644 --- a/ios/web/shell/test/earl_grey/web_shell_test_case.mm +++ b/ios/web/shell/test/earl_grey/web_shell_test_case.mm
@@ -4,17 +4,13 @@ #import "ios/web/shell/test/earl_grey/web_shell_test_case.h" +#import "ios/testing/earl_grey/earl_grey_test.h" #import "ios/web/public/test/http_server/http_server.h" #if defined(CHROME_EARL_GREY_1) -#import <EarlGrey/EarlGrey.h> // nogncheck #include "testing/coverage_util_ios.h" // nogncheck #endif -#if defined(CHROME_EARL_GREY_2) -#import "ios/third_party/earl_grey2/src/TestLib/EarlGreyImpl/EarlGrey.h" // nogncheck -#endif - #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif
diff --git a/ios/web_view/internal/sync/web_view_device_info_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_device_info_sync_service_factory.mm index b65fde8..8fd166a89 100644 --- a/ios/web_view/internal/sync/web_view_device_info_sync_service_factory.mm +++ b/ios/web_view/internal/sync/web_view_device_info_sync_service_factory.mm
@@ -54,7 +54,7 @@ WebViewBrowserState::FromBrowserState(context); auto local_device_info_provider = std::make_unique<syncer::LocalDeviceInfoProviderImpl>( - version_info::Channel::UNKNOWN, version_info::GetVersionNumber(), + version_info::Channel::STABLE, version_info::GetVersionNumber(), ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET, /*signin_scoped_device_id_callback=*/ base::BindRepeating(&signin::GetSigninScopedDeviceId,
diff --git a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm index f9e79001..ebf00175 100644 --- a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm +++ b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
@@ -98,7 +98,7 @@ base::BindRepeating(&RequestProxyResolvingSocketFactory, context), browser_state->GetSharedURLLoaderFactory(), ApplicationContext::GetInstance()->GetNetworkConnectionTracker(), - version_info::Channel::UNKNOWN, GetProductCategoryForSubtypes(), + version_info::Channel::STABLE, GetProductCategoryForSubtypes(), WebViewIdentityManagerFactory::GetForBrowserState(browser_state), base::WrapUnique(new gcm::GCMClientFactory), base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::UI}),
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm index 35c88a3..33003c7 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.mm +++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -81,8 +81,7 @@ browser_state_, ServiceAccessType::IMPLICIT_ACCESS); component_factory_.reset(new browser_sync::ProfileSyncComponentsFactoryImpl( - this, version_info::Channel::UNKNOWN, - prefs::kSavingBrowserHistoryDisabled, + this, version_info::Channel::STABLE, prefs::kSavingBrowserHistoryDisabled, base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::UI}), db_thread_, profile_web_data_service_, account_web_data_service_, password_store_,
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn index d7f7763..2e10ae7f 100644 --- a/media/base/android/BUILD.gn +++ b/media/base/android/BUILD.gn
@@ -154,6 +154,13 @@ ] } + java_cpp_strings("java_switches") { + sources = [ + "//media/base/media_switches.cc", + ] + template = "//media/base/android/java_templates/MediaSwitches.java.tmpl" + } + android_resources("media_java_resources") { custom_package = "org.chromium.media" resource_dirs = [ "java/res" ] @@ -167,6 +174,7 @@ ] srcjar_deps = [ ":java_enums", + ":java_switches", "//media/base:java_enums", ] java_files = [ @@ -187,7 +195,6 @@ "java/src/org/chromium/media/MediaPlayerBridge.java", "java/src/org/chromium/media/MediaPlayerListener.java", "java/src/org/chromium/media/MediaServerCrashListener.java", - "java/src/org/chromium/media/MediaSwitches.java", ] }
diff --git a/media/base/android/java/src/org/chromium/media/MediaSwitches.java b/media/base/android/java_templates/MediaSwitches.java.tmpl similarity index 86% rename from media/base/android/java/src/org/chromium/media/MediaSwitches.java rename to media/base/android/java_templates/MediaSwitches.java.tmpl index 4f11b45..bac4c74 100644 --- a/media/base/android/java/src/org/chromium/media/MediaSwitches.java +++ b/media/base/android/java_templates/MediaSwitches.java.tmpl
@@ -7,7 +7,7 @@ /** * Contains command line switches that are specific to the media layer. */ -public abstract class MediaSwitches { +public abstract class MediaSwitches {{ // Set the autoplay policy to ignore user gesture requirements public static final String AUTOPLAY_NO_GESTURE_REQUIRED_POLICY = "autoplay-policy=no-user-gesture-required"; @@ -15,6 +15,8 @@ // TODO(819383): Remove this and its usage. public static final String USE_MODERN_MEDIA_CONTROLS = "UseModernMediaControls"; +{NATIVE_STRINGS} + // Prevents instantiation. - private MediaSwitches() {} -} + private MediaSwitches() {{}} +}}
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc index aff9a78b..77670d0 100644 --- a/media/base/video_decoder_config.cc +++ b/media/base/video_decoder_config.cc
@@ -83,6 +83,11 @@ VideoDecoderConfig::~VideoDecoderConfig() = default; +void VideoDecoderConfig::set_color_space_info( + const VideoColorSpace& color_space) { + color_space_info_ = color_space; +} + const VideoColorSpace& VideoDecoderConfig::color_space_info() const { return color_space_info_; }
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h index fa52c39..bd65211 100644 --- a/media/base/video_decoder_config.h +++ b/media/base/video_decoder_config.h
@@ -137,6 +137,7 @@ } // Color space of the image data. + void set_color_space_info(const VideoColorSpace& color_space); const VideoColorSpace& color_space_info() const; // Dynamic range of the image data.
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc index f02d270..f5e776f9 100644 --- a/media/blink/multibuffer_data_source.cc +++ b/media/blink/multibuffer_data_source.cc
@@ -289,6 +289,10 @@ return url_data_->is_cors_cross_origin(); } +bool MultibufferDataSource::HasAccessControl() const { + return url_data_->has_access_control(); +} + UrlData::CorsMode MultibufferDataSource::cors_mode() const { return url_data_->cors_mode(); }
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h index 51b3cb4c..9e3a38c0 100644 --- a/media/blink/multibuffer_data_source.h +++ b/media/blink/multibuffer_data_source.h
@@ -82,6 +82,10 @@ // This must be called after the response arrives. bool IsCorsCrossOrigin() const; + // Returns true if the response includes an Access-Control-Allow-Origin + // header (that is not "null"). + bool HasAccessControl() const; + // Returns the CorsMode of the underlying UrlData. UrlData::CorsMode cors_mode() const;
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc index b79632c2..c455cdc 100644 --- a/media/blink/resource_multibuffer_data_provider.cc +++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -331,6 +331,18 @@ destination_url_data->set_is_cors_cross_origin( network::cors::IsCorsCrossOriginResponseType(response_type)); + // Only used for metrics. + { + WebString access_control = + response.HttpHeaderField("Access-Control-Allow-Origin"); + if (!access_control.IsEmpty() && !access_control.Equals("null")) { + // Note: When |access_control| is not *, we should verify that it matches + // the requesting origin. Instead we just assume that it matches, which is + // probably accurate enough for metrics. + destination_url_data->set_has_access_control(); + } + } + if (destination_url_data != url_data_) { // At this point, we've encountered a redirect, or found a better url data // instance for the data that we're about to download.
diff --git a/media/blink/url_index.cc b/media/blink/url_index.cc index d3c381a..fb940a4 100644 --- a/media/blink/url_index.cc +++ b/media/blink/url_index.cc
@@ -49,6 +49,7 @@ : url_(url), have_data_origin_(false), cors_mode_(cors_mode), + has_access_control_(false), url_index_(url_index), length_(kPositionNotSpecified), range_supported_(false), @@ -90,6 +91,7 @@ bytes_read_from_cache_ += other->bytes_read_from_cache_; // is_cors_corss_origin_ will not relax from true to false. set_is_cors_cross_origin(other->is_cors_cross_origin_); + has_access_control_ |= other->has_access_control_; multibuffer()->MergeFrom(other->multibuffer()); } } @@ -112,6 +114,10 @@ is_cors_cross_origin_ = is_cors_cross_origin; } +void UrlData::set_has_access_control() { + has_access_control_ = true; +} + void UrlData::RedirectTo(const scoped_refptr<UrlData>& url_data) { DCHECK(thread_checker_.CalledOnValidThread()); // Copy any cached data over to the new location.
diff --git a/media/blink/url_index.h b/media/blink/url_index.h index 1c933968..797b9e82 100644 --- a/media/blink/url_index.h +++ b/media/blink/url_index.h
@@ -67,6 +67,8 @@ // Cross-origin access mode CorsMode cors_mode() const { return cors_mode_; } + bool has_access_control() const { return has_access_control_; } + // Are HTTP range requests supported? bool range_supported() const { return range_supported_; } @@ -122,6 +124,7 @@ void set_last_modified(base::Time last_modified); void set_etag(const std::string& etag); void set_is_cors_cross_origin(bool is_cors_cross_origin); + void set_has_access_control(); // A redirect has occured (or we've found a better UrlData for the same // resource). @@ -182,6 +185,7 @@ // Cross-origin access mode. const CorsMode cors_mode_; + bool has_access_control_; UrlIndex* const url_index_; @@ -197,7 +201,7 @@ // Does the server support ranges? bool range_supported_; - // Set to false if we have reason to beleive the chrome disk cache + // Set to false if we have reason to believe the chrome disk cache // will not cache this url. bool cacheable_;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index dc85f7e..e0c9a7e 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -1622,11 +1622,17 @@ // URL, since MediaPlayer doesn't support data:// URLs, fail playback now. const bool found_hls = status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS; if (found_hls && mb_data_source_) { + demuxer_found_hls_ = true; + UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin", mb_data_source_->IsCorsCrossOrigin()); - // Note: Does not consider the full redirect chain. Redirecting through - // another origin will set WouldTaintOrigin() though, assuming that the - // crossorigin attribute is not set. + if (mb_data_source_->IsCorsCrossOrigin()) { + UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl", + mb_data_source_->HasAccessControl()); + } + + // Note: Does not consider the full redirect chain, which could contain + // undetected mixed content. bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin()) .GetURL() .SchemeIsCryptographic(); @@ -1636,10 +1642,6 @@ UMA_HISTOGRAM_BOOLEAN( "Media.WebMediaPlayerImpl.HLS.IsMixedContent", frame_url_is_cryptographic && !manifest_url_is_cryptographic); - UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.WouldTaintOrigin", - WouldTaintOrigin()); - // Note: Affects WouldTaintOrigin(). - demuxer_found_hls_ = true; renderer_factory_selector_->SetUseMediaPlayer(true);
diff --git a/media/gpu/android/avda_shared_state.cc b/media/gpu/android/avda_shared_state.cc index ea79328..2d5e1c1b 100644 --- a/media/gpu/android/avda_shared_state.cc +++ b/media/gpu/android/avda_shared_state.cc
@@ -48,6 +48,8 @@ void AVDASharedState::UpdateTexImage() { texture_owner()->UpdateTexImage(); + if (!texture_owner()->binds_texture_on_update()) + texture_owner()->EnsureTexImageBound(); // Helpfully, this is already column major. texture_owner()->GetTransformMatrix(gl_matrix_); }
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc index 5cf2987..ba5dfb4 100644 --- a/media/gpu/android/codec_image.cc +++ b/media/gpu/android/codec_image.cc
@@ -96,7 +96,7 @@ if (bound_service_id != static_cast<GLint>(texture_owner_->GetTextureId())) return false; - RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestore); + RenderToTextureOwnerFrontBuffer(BindingsMode::kEnsureTexImageBound); return true; } @@ -155,7 +155,7 @@ // The matrix is available after we render to the front buffer. If that fails // we'll return the matrix from the previous frame, which is more likely to be // correct than the identity matrix anyway. - RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestore); + RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestoreIfBound); texture_owner_->GetTransformMatrix(matrix); YInvertMatrix(matrix); } @@ -176,8 +176,10 @@ } bool CodecImage::RenderToFrontBuffer() { + // This code is used to trigger early rendering of the image before it is used + // for compositing, there is no need to bind the image. return texture_owner_ - ? RenderToTextureOwnerFrontBuffer(BindingsMode::kRestore) + ? RenderToTextureOwnerFrontBuffer(BindingsMode::kRestoreIfBound) : RenderToOverlay(); } @@ -202,13 +204,13 @@ return true; } -bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode, - bool bind_egl_image) { +bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode) { DCHECK(texture_owner_); - DCHECK(bind_egl_image); - if (phase_ == Phase::kInFrontBuffer) + if (phase_ == Phase::kInFrontBuffer) { + EnsureBoundIfNeeded(bindings_mode); return true; + } if (phase_ == Phase::kInvalidated) return false; @@ -223,23 +225,31 @@ std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded(texture_owner_.get()); - // If we have to switch contexts, then we always want to restore the - // bindings. Also if bind_egl_image is set to false, we do no need to restore - // any bindings since UpdateTexImage will not bind any egl image to the - // texture target. + // If updating the image will implicitly update the texture bindings then + // restore if requested or the update needed a context switch. bool should_restore_bindings = - (bindings_mode == BindingsMode::kRestore || !!scoped_make_current) && - bind_egl_image; + texture_owner_->binds_texture_on_update() && + (bindings_mode == BindingsMode::kRestoreIfBound || !!scoped_make_current); GLint bound_service_id = 0; if (should_restore_bindings) glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); - texture_owner_->UpdateTexImage(bind_egl_image); + texture_owner_->UpdateTexImage(); + EnsureBoundIfNeeded(bindings_mode); if (should_restore_bindings) glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); return true; } +void CodecImage::EnsureBoundIfNeeded(BindingsMode mode) { + DCHECK(texture_owner_); + + if (texture_owner_->binds_texture_on_update() || + mode != BindingsMode::kEnsureTexImageBound) + return; + texture_owner_->EnsureTexImageBound(); +} + bool CodecImage::RenderToOverlay() { if (phase_ == Phase::kInFrontBuffer) return true; @@ -263,7 +273,7 @@ CodecImage::GetAHardwareBuffer() { DCHECK(texture_owner_); - RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestore); + RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestoreIfBound); return texture_owner_->GetAHardwareBuffer(); }
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h index f435e1b..afbcf6e 100644 --- a/media/gpu/android/codec_image.h +++ b/media/gpu/android/codec_image.h
@@ -106,17 +106,22 @@ // Renders this image to the texture owner front buffer by first rendering // it to the back buffer if it's not already there, and then waiting for the - // frame available event before calling UpdateTexImage(). Passing - // BindingsMode::kDontRestore skips the work of restoring the current texture - // bindings if the texture owner's context is already current. Otherwise, - // this switches contexts and preserves the texture bindings. Setting - // |bind_egl_image| = false skips doing the egl bindings to the texture target - // during texture update. |bind_egl_image| must always be true when using a - // SurfaceTexture backed CodecImage(TextureOwner). Returns true if the buffer - // is in the front buffer. Returns false if the buffer was invalidated. - enum class BindingsMode { kRestore, kDontRestore }; - bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode, - bool bind_egl_image = true); + // frame available event before calling UpdateTexImage(). + enum class BindingsMode { + // Ensures that the TextureOwner's texture is bound to the latest image, if + // it requires explicit binding. + kEnsureTexImageBound, + + // Updates the current image but does not bind it. If updating the image + // implicitly binds the texture, the current bindings will be restored. + kRestoreIfBound, + + // Updates the current image but does not bind it. If updating the image + // implicitly binds the texture, the current bindings will not be restored. + kDontRestoreIfBound + }; + bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode); + void EnsureBoundIfNeeded(BindingsMode mode); // Renders this image to the overlay. Returns true if the buffer is in the // overlay front buffer. Returns false if the buffer was invalidated.
diff --git a/media/gpu/android/codec_image_unittest.cc b/media/gpu/android/codec_image_unittest.cc index a0f9027..42794da 100644 --- a/media/gpu/android/codec_image_unittest.cc +++ b/media/gpu/android/codec_image_unittest.cc
@@ -61,8 +61,8 @@ // The tests rely on this texture being bound. glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_); - texture_owner_ = new NiceMock<MockTextureOwner>(texture_id_, context_.get(), - surface_.get()); + texture_owner_ = new NiceMock<MockTextureOwner>( + texture_id_, context_.get(), surface_.get(), BindsTextureOnUpdate()); } void TearDown() override { @@ -90,6 +90,8 @@ return image; } + virtual bool BindsTextureOnUpdate() { return true; } + base::test::ScopedTaskEnvironment scoped_task_environment_; NiceMock<MockMediaCodecBridge>* codec_; std::unique_ptr<CodecWrapper> wrapper_; @@ -107,6 +109,10 @@ PromotionHintReceiver promotion_hint_receiver_; }; +class CodecImageTestExplicitBind : public CodecImageTest { + bool BindsTextureOnUpdate() override { return false; } +}; + TEST_F(CodecImageTest, DestructionCbRuns) { base::MockCallback<CodecImage::DestructionCb> cb; auto i = NewImage(kOverlay, cb.Get()); @@ -156,7 +162,19 @@ InSequence s; EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); EXPECT_CALL(*texture_owner_, WaitForFrameAvailable()); - EXPECT_CALL(*texture_owner_, UpdateTexImage(true)); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); + i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES); + ASSERT_TRUE(i->was_rendered_to_front_buffer()); +} + +TEST_F(CodecImageTestExplicitBind, CopyTexImageTriggersFrontBufferRendering) { + auto i = NewImage(kTextureOwner); + // Verify that the release comes before the wait. + InSequence s; + EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); + EXPECT_CALL(*texture_owner_, WaitForFrameAvailable()); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); + EXPECT_CALL(*texture_owner_, EnsureTexImageBound()); i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES); ASSERT_TRUE(i->was_rendered_to_front_buffer()); } @@ -166,7 +184,23 @@ InSequence s; EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); EXPECT_CALL(*texture_owner_, WaitForFrameAvailable()); - EXPECT_CALL(*texture_owner_, UpdateTexImage(true)); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); + EXPECT_CALL(*texture_owner_, GetTransformMatrix(_)); + float matrix[16]; + i->GetTextureMatrix(matrix); + ASSERT_TRUE(i->was_rendered_to_front_buffer()); +} + +TEST_F(CodecImageTestExplicitBind, + GetTextureMatrixTriggersFrontBufferRendering) { + // GetTextureMatrix should not bind the image. + texture_owner_->expect_update_tex_image = false; + + auto i = NewImage(kTextureOwner); + InSequence s; + EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); + EXPECT_CALL(*texture_owner_, WaitForFrameAvailable()); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); EXPECT_CALL(*texture_owner_, GetTransformMatrix(_)); float matrix[16]; i->GetTextureMatrix(matrix); @@ -245,7 +279,21 @@ glGenTextures(1, &pre_bound_texture); glBindTexture(GL_TEXTURE_EXTERNAL_OES, pre_bound_texture); auto i = NewImage(kTextureOwner); - EXPECT_CALL(*texture_owner_, UpdateTexImage(true)); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); + i->RenderToFrontBuffer(); + GLint post_bound_texture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &post_bound_texture); + ASSERT_EQ(pre_bound_texture, static_cast<GLuint>(post_bound_texture)); +} + +TEST_F(CodecImageTestExplicitBind, RenderToFrontBufferDoesNotBindTexture) { + texture_owner_->expect_update_tex_image = false; + + GLuint pre_bound_texture = 0; + glGenTextures(1, &pre_bound_texture); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, pre_bound_texture); + auto i = NewImage(kTextureOwner); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); i->RenderToFrontBuffer(); GLint post_bound_texture = 0; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &post_bound_texture); @@ -264,7 +312,7 @@ auto i = NewImage(kTextureOwner); // Our context should not be current when UpdateTexImage() is called. - EXPECT_CALL(*texture_owner_, UpdateTexImage(true)).WillOnce(Invoke([&](bool) { + EXPECT_CALL(*texture_owner_, UpdateTexImage()).WillOnce(Invoke([&]() { ASSERT_FALSE(context->IsCurrent(surface.get())); })); i->RenderToFrontBuffer(); @@ -299,7 +347,7 @@ EXPECT_EQ(texture_owner_->get_a_hardware_buffer_count, 0); EXPECT_FALSE(i->was_rendered_to_front_buffer()); - EXPECT_CALL(*texture_owner_, UpdateTexImage(true)); + EXPECT_CALL(*texture_owner_, UpdateTexImage()); i->GetAHardwareBuffer(); EXPECT_EQ(texture_owner_->get_a_hardware_buffer_count, 1); EXPECT_TRUE(i->was_rendered_to_front_buffer());
diff --git a/media/gpu/android/image_reader_gl_owner.cc b/media/gpu/android/image_reader_gl_owner.cc index abc0418..5faf959 100644 --- a/media/gpu/android/image_reader_gl_owner.cc +++ b/media/gpu/android/image_reader_gl_owner.cc
@@ -77,7 +77,8 @@ ImageReaderGLOwner::ImageReaderGLOwner( std::unique_ptr<gpu::gles2::AbstractTexture> texture, Mode mode) - : TextureOwner(std::move(texture)), + : TextureOwner(false /* binds_texture_on_image_update */, + std::move(texture)), current_image_(nullptr), loader_(base::android::AndroidImageReader::GetInstance()), context_(gl::GLContext::GetCurrent()), @@ -185,7 +186,7 @@ return gl::ScopedJavaSurface::AcquireExternalSurface(j_surface); } -void ImageReaderGLOwner::UpdateTexImage(bool bind_egl_image) { +void ImageReaderGLOwner::UpdateTexImage() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // If we've lost the texture, then do nothing. @@ -250,13 +251,6 @@ current_image_ = image; current_image_fence_ = std::move(scoped_acquire_fence_fd); current_image_bound_ = false; - - // Skip generating and binding egl image if bind_egl_image is false. - if (bind_egl_image) { - // TODO(khushalsagar): This should be on the public API so that we only bind - // the texture if we were going to render it without an overlay. - EnsureTexImageBound(); - } } void ImageReaderGLOwner::EnsureTexImageBound() {
diff --git a/media/gpu/android/image_reader_gl_owner.h b/media/gpu/android/image_reader_gl_owner.h index d52f73f..4ad5a35 100644 --- a/media/gpu/android/image_reader_gl_owner.h +++ b/media/gpu/android/image_reader_gl_owner.h
@@ -34,7 +34,8 @@ gl::GLContext* GetContext() const override; gl::GLSurface* GetSurface() const override; gl::ScopedJavaSurface CreateJavaSurface() const override; - void UpdateTexImage(bool bind_egl_image) override; + void UpdateTexImage() override; + void EnsureTexImageBound() override; void GetTransformMatrix(float mtx[16]) override; void ReleaseBackBuffers() override; void SetReleaseTimeToNow() override; @@ -62,8 +63,6 @@ // error. bool MaybeDeleteCurrentImage(); - void EnsureTexImageBound(); - // Releases an external ref on the image, with the fence that must be signaled // before the |image| can be resued by the AImageReader. void ReleaseRefOnImage(AImage* image, base::ScopedFD fence_fd);
diff --git a/media/gpu/android/mock_texture_owner.cc b/media/gpu/android/mock_texture_owner.cc index 9cb0b23..037ccd2 100644 --- a/media/gpu/android/mock_texture_owner.cc +++ b/media/gpu/android/mock_texture_owner.cc
@@ -13,11 +13,14 @@ MockTextureOwner::MockTextureOwner(GLuint fake_texture_id, gl::GLContext* fake_context, - gl::GLSurface* fake_surface) - : TextureOwner(std::make_unique<MockAbstractTexture>(fake_texture_id)), + gl::GLSurface* fake_surface, + bool binds_texture_on_update) + : TextureOwner(binds_texture_on_update, + std::make_unique<MockAbstractTexture>(fake_texture_id)), fake_context(fake_context), fake_surface(fake_surface), - expecting_frame_available(false) { + expecting_frame_available(false), + expect_update_tex_image(!binds_texture_on_update) { ON_CALL(*this, GetTextureId()).WillByDefault(Return(fake_texture_id)); ON_CALL(*this, GetContext()).WillByDefault(Return(fake_context)); ON_CALL(*this, GetSurface()).WillByDefault(Return(fake_surface)); @@ -31,6 +34,9 @@ ON_CALL(*this, WaitForFrameAvailable()) .WillByDefault( Invoke(this, &MockTextureOwner::FakeWaitForFrameAvailable)); + ON_CALL(*this, EnsureTexImageBound()).WillByDefault(Invoke([this] { + CHECK(expect_update_tex_image); + })); } MockTextureOwner::~MockTextureOwner() {
diff --git a/media/gpu/android/mock_texture_owner.h b/media/gpu/android/mock_texture_owner.h index adcff47..c5f06c0b 100644 --- a/media/gpu/android/mock_texture_owner.h +++ b/media/gpu/android/mock_texture_owner.h
@@ -22,13 +22,15 @@ public: MockTextureOwner(GLuint fake_texture_id, gl::GLContext* fake_context, - gl::GLSurface* fake_surface); + gl::GLSurface* fake_surface, + bool binds_texture_on_update = false); MOCK_CONST_METHOD0(GetTextureId, GLuint()); MOCK_CONST_METHOD0(GetContext, gl::GLContext*()); MOCK_CONST_METHOD0(GetSurface, gl::GLSurface*()); MOCK_CONST_METHOD0(CreateJavaSurface, gl::ScopedJavaSurface()); - MOCK_METHOD1(UpdateTexImage, void(bool bind_egl_image)); + MOCK_METHOD0(UpdateTexImage, void()); + MOCK_METHOD0(EnsureTexImageBound, void()); MOCK_METHOD1(GetTransformMatrix, void(float mtx[16])); MOCK_METHOD0(ReleaseBackBuffers, void()); MOCK_METHOD0(SetReleaseTimeToNow, void()); @@ -53,6 +55,7 @@ gl::GLSurface* fake_surface; bool expecting_frame_available; int get_a_hardware_buffer_count = 0; + bool expect_update_tex_image; protected: ~MockTextureOwner();
diff --git a/media/gpu/android/surface_texture_gl_owner.cc b/media/gpu/android/surface_texture_gl_owner.cc index af0da9b..f19f2ad4 100644 --- a/media/gpu/android/surface_texture_gl_owner.cc +++ b/media/gpu/android/surface_texture_gl_owner.cc
@@ -37,7 +37,7 @@ SurfaceTextureGLOwner::SurfaceTextureGLOwner( std::unique_ptr<gpu::gles2::AbstractTexture> texture) - : TextureOwner(std::move(texture)), + : TextureOwner(true /*binds_texture_on_update */, std::move(texture)), surface_texture_(gl::SurfaceTexture::Create(GetTextureId())), context_(gl::GLContext::GetCurrent()), surface_(gl::GLSurface::GetCurrent()), @@ -68,15 +68,16 @@ return gl::ScopedJavaSurface(surface_texture_.get()); } -// bind_egl_image is a no-op for surface texture since it always binds the egl -// image under the hood. -void SurfaceTextureGLOwner::UpdateTexImage(bool bind_egl_image) { +void SurfaceTextureGLOwner::UpdateTexImage() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(bind_egl_image); if (surface_texture_) surface_texture_->UpdateTexImage(); } +void SurfaceTextureGLOwner::EnsureTexImageBound() { + NOTREACHED(); +} + void SurfaceTextureGLOwner::GetTransformMatrix(float mtx[]) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // If we don't have a SurfaceTexture, then the matrix doesn't matter. We
diff --git a/media/gpu/android/surface_texture_gl_owner.h b/media/gpu/android/surface_texture_gl_owner.h index a65c48e..f2634aaac 100644 --- a/media/gpu/android/surface_texture_gl_owner.h +++ b/media/gpu/android/surface_texture_gl_owner.h
@@ -33,7 +33,8 @@ gl::GLContext* GetContext() const override; gl::GLSurface* GetSurface() const override; gl::ScopedJavaSurface CreateJavaSurface() const override; - void UpdateTexImage(bool bind_egl_image) override; + void UpdateTexImage() override; + void EnsureTexImageBound() override; void GetTransformMatrix(float mtx[16]) override; void ReleaseBackBuffers() override; void SetReleaseTimeToNow() override;
diff --git a/media/gpu/android/texture_owner.cc b/media/gpu/android/texture_owner.cc index bf2f4ee8..60b57ffe 100644 --- a/media/gpu/android/texture_owner.cc +++ b/media/gpu/android/texture_owner.cc
@@ -15,9 +15,11 @@ namespace media { -TextureOwner::TextureOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture) +TextureOwner::TextureOwner(bool binds_texture_on_update, + std::unique_ptr<gpu::gles2::AbstractTexture> texture) : base::RefCountedDeleteOnSequence<TextureOwner>( base::ThreadTaskRunnerHandle::Get()), + binds_texture_on_update_(binds_texture_on_update), texture_(std::move(texture)), task_runner_(base::ThreadTaskRunnerHandle::Get()) { // Notify the subclass when the texture is destroyed.
diff --git a/media/gpu/android/texture_owner.h b/media/gpu/android/texture_owner.h index 329ccd1..c8d59ad2 100644 --- a/media/gpu/android/texture_owner.h +++ b/media/gpu/android/texture_owner.h
@@ -73,9 +73,12 @@ virtual gl::ScopedJavaSurface CreateJavaSurface() const = 0; // Update the texture image using the latest available image data. - // |bind_egl_image| hints the underlying implementation whether an egl image - // should be bound to the texture target or not. - virtual void UpdateTexImage(bool bind_egl_image = true) = 0; + virtual void UpdateTexImage() = 0; + + // Ensures that the latest texture image is bound to the texture target. + // Should only be used if the TextureOwner requires explicit binding of the + // image after an update. + virtual void EnsureTexImageBound() = 0; // Transformation matrix if any associated with the texture image. virtual void GetTransformMatrix(float mtx[16]) = 0; @@ -106,12 +109,15 @@ virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> GetAHardwareBuffer() = 0; + bool binds_texture_on_update() const { return binds_texture_on_update_; } + protected: friend class base::RefCountedDeleteOnSequence<TextureOwner>; friend class base::DeleteHelper<TextureOwner>; // |texture| is the texture that we'll own. - TextureOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture); + TextureOwner(bool binds_texture_on_update, + std::unique_ptr<gpu::gles2::AbstractTexture> texture); virtual ~TextureOwner(); // Drop |texture_| immediately. Will call OnTextureDestroyed immediately if @@ -128,6 +134,10 @@ gpu::gles2::AbstractTexture* texture() const { return texture_.get(); } private: + // Set to true if the updating the image for this owner will automatically + // bind it to the texture target. + const bool binds_texture_on_update_; + std::unique_ptr<gpu::gles2::AbstractTexture> texture_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/media/gpu/ipc/service/vda_video_decoder.cc b/media/gpu/ipc/service/vda_video_decoder.cc index 2b94759..4daed39 100644 --- a/media/gpu/ipc/service/vda_video_decoder.cc +++ b/media/gpu/ipc/service/vda_video_decoder.cc
@@ -277,11 +277,17 @@ false; #endif + // Hardware decoders require ColorSpace to be set beforehand to provide + // correct HDR output. + const bool is_hdr_color_space_change = + config_.profile() == media::VP9PROFILE_PROFILE2 && + config_.color_space_info() != config.color_space_info(); + // The configuration is supported. config_ = config; if (reinitializing) { - if (is_profile_change) { + if (is_profile_change || is_hdr_color_space_change) { MEDIA_LOG(INFO, media_log_) << "Reinitializing video decode accelerator " << "for profile change"; gpu_task_runner_->PostTask(
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc index 137d1b43..421fe56 100644 --- a/media/gpu/video_decode_accelerator_tests.cc +++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -98,28 +98,6 @@ EXPECT_TRUE(tvp->WaitForFrameProcessors()); } -// Flush the decoder immediately after doing a mid-stream reset, without waiting -// for a kResetDone event. -TEST_F(VideoDecoderTest, FlushBeforeResetDone) { - auto tvp = CreateVideoPlayer(g_env->video_); - - tvp->Play(); - EXPECT_TRUE(tvp->WaitForFrameDecoded(g_env->video_->NumFrames() / 2)); - tvp->Reset(); - tvp->Flush(); - EXPECT_TRUE(tvp->WaitForResetDone()); - EXPECT_TRUE(tvp->WaitForFlushDone()); - - // As flush doesn't cancel reset, we should have received a single kResetDone - // and kFlushDone event. We didn't decode the entire video, but more frames - // might be decoded by the time we called reset, so we can only check whether - // the decoded frame count is <= the total number of frames. - EXPECT_EQ(tvp->GetResetDoneCount(), 1u); - EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); - EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_TRUE(tvp->WaitForFrameProcessors()); -} - // Reset the decoder immediately after initialization. TEST_F(VideoDecoderTest, ResetAfterInitialize) { auto tvp = CreateVideoPlayer(g_env->video_);
diff --git a/media/learning/common/learning_task_controller.h b/media/learning/common/learning_task_controller.h index 7af3f63b..65cd91f6 100644 --- a/media/learning/common/learning_task_controller.h +++ b/media/learning/common/learning_task_controller.h
@@ -14,6 +14,21 @@ namespace media { namespace learning { +// Wrapper struct for completing an observation via LearningTaskController. +// Most callers will just send in a TargetValue, so this lets us provide a +// default weight. Further, a few callers will add optional data, like the UKM +// SourceId, which most callers don't care about. +struct ObservationCompletion { + ObservationCompletion() = default; + /* implicit */ ObservationCompletion(const TargetValue& target) + : target_value(target) {} + ObservationCompletion(const TargetValue& target, WeightType w) + : target_value(target), weight(w) {} + + TargetValue target_value; + WeightType weight = 1u; +}; + // Client for a single learning task. Intended to be the primary API for client // code that generates FeatureVectors / requests predictions for a single task. // The API supports sending in an observed FeatureVector without a target value, @@ -25,10 +40,12 @@ LearningTaskController() = default; virtual ~LearningTaskController() = default; - // Used to set the target value and example weight. - using SetTargetValueCB = base::OnceCallback<void(TargetValue, WeightType)>; + // TODO(liberato): what is the scope of this id? can it be local to whoever + // owns the LTC? otherwise, consider making it an unguessable token. + // TODO(liberato): consider making a special id that means "i will not send a + // target value", to save a call to CancelObservation. + using ObservationId = int32_t; - // Record a FeatureVector that may be used for prediction and / or adding a // new example. Call this at the time one would try to predict the // TargetValue. This lets the framework snapshot any framework-provided // feature values at prediction time. Later, if you want to turn these @@ -39,7 +56,15 @@ // TODO(liberato): See if this ends up generating smaller code with pass-by- // value or with |FeatureVector&&|, once we have callers that can actually // benefit from it. - virtual SetTargetValueCB BeginObservation(const FeatureVector& features) = 0; + virtual void BeginObservation(ObservationId id, + const FeatureVector& features) = 0; + + // Complete an observation by sending a completion. + virtual void CompleteObservation(ObservationId id, + const ObservationCompletion& completion) = 0; + + // Notify the LTC that no completion will be sent. + virtual void CancelObservation(ObservationId id) = 0; private: DISALLOW_COPY_AND_ASSIGN(LearningTaskController);
diff --git a/media/learning/impl/learning_session_impl.cc b/media/learning/impl/learning_session_impl.cc index 176cb00..4ad7de4 100644 --- a/media/learning/impl/learning_session_impl.cc +++ b/media/learning/impl/learning_session_impl.cc
@@ -37,8 +37,10 @@ if (iter != task_map_.end()) { // TODO(liberato): We shouldn't be adding examples. We should provide the // LearningTaskController instead, although ownership gets a bit weird. - iter->second->BeginObservation(example.features) - .Run(example.target_value, example.weight); + LearningTaskController::ObservationId id = 1; + iter->second->BeginObservation(id, example.features); + iter->second->CompleteObservation( + id, ObservationCompletion(example.target_value, example.weight)); } }
diff --git a/media/learning/impl/learning_session_impl_unittest.cc b/media/learning/impl/learning_session_impl_unittest.cc index 5cc7ac03..5c55d66 100644 --- a/media/learning/impl/learning_session_impl_unittest.cc +++ b/media/learning/impl/learning_session_impl_unittest.cc
@@ -32,20 +32,25 @@ } } - SetTargetValueCB BeginObservation(const FeatureVector& features) override { - return base::BindOnce(&FakeLearningTaskController::AddExample, - base::Unretained(this), features); + void BeginObservation(ObservationId id, + const FeatureVector& features) override { + id_ = id; + features_ = features; } - void AddExample(FeatureVector features, - TargetValue target, - WeightType weight) { - example_.features = std::move(features); - example_.target_value = target; - example_.weight = weight; + void CompleteObservation(ObservationId id, + const ObservationCompletion& completion) override { + EXPECT_EQ(id_, id); + example_.features = std::move(features_); + example_.target_value = completion.target_value; + example_.weight = completion.weight; } + void CancelObservation(ObservationId id) override { ASSERT_TRUE(false); } + SequenceBoundFeatureProvider feature_provider_; + ObservationId id_ = 0; + FeatureVector features_; LabelledExample example_; };
diff --git a/media/learning/impl/learning_task_controller_helper.cc b/media/learning/impl/learning_task_controller_helper.cc index dc82675b..d4d57b4 100644 --- a/media/learning/impl/learning_task_controller_helper.cc +++ b/media/learning/impl/learning_task_controller_helper.cc
@@ -13,28 +13,6 @@ namespace media { namespace learning { -class RunOnDelete { - public: - RunOnDelete(scoped_refptr<base::SequencedTaskRunner> task_runner, - base::OnceClosure cb) - : task_runner_(std::move(task_runner)), cb_(std::move(cb)) {} - - ~RunOnDelete() { - if (task_runner_) - task_runner_->PostTask(FROM_HERE, std::move(cb_)); - } - - // Don't do anything on delete. - void Cancel() { - task_runner_ = nullptr; - cb_ = base::OnceClosure(); - } - - private: - scoped_refptr<base::SequencedTaskRunner> task_runner_; - base::OnceClosure cb_; -}; - LearningTaskControllerHelper::LearningTaskControllerHelper( const LearningTask& task, AddExampleCB add_example_cb, @@ -46,52 +24,36 @@ LearningTaskControllerHelper::~LearningTaskControllerHelper() = default; -LearningTaskController::SetTargetValueCB -LearningTaskControllerHelper::BeginObservation(FeatureVector features) { - int64_t example_id = next_example_id_++; - auto& pending_example = pending_examples_[example_id]; +void LearningTaskControllerHelper::BeginObservation(ObservationId id, + FeatureVector features) { + auto& pending_example = pending_examples_[id]; // Start feature prediction, so that we capture the current values. if (!feature_provider_.is_null()) { feature_provider_.Post( FROM_HERE, &FeatureProvider::AddFeatures, std::move(features), base::BindOnce(&LearningTaskControllerHelper::OnFeaturesReadyTrampoline, - task_runner_, AsWeakPtr(), example_id)); + task_runner_, AsWeakPtr(), id)); } else { pending_example.example.features = std::move(features); pending_example.features_done = true; } - - return base::BindOnce( - &LearningTaskControllerHelper::OnTargetValue, AsWeakPtr(), example_id, - std::make_unique<RunOnDelete>( - task_runner_, - base::BindOnce( - &LearningTaskControllerHelper::OnLabelCallbackDestroyed, - AsWeakPtr(), example_id))); } -void LearningTaskControllerHelper::OnTargetValue( - int64_t example_id, - std::unique_ptr<RunOnDelete> run_on_delete, - TargetValue target_value, - WeightType weight) { - // Don't bother to run the callback when |run_on_delete| is destroyed. - run_on_delete->Cancel(); - run_on_delete = nullptr; - - auto iter = pending_examples_.find(example_id); +void LearningTaskControllerHelper::CompleteObservation( + ObservationId id, + const ObservationCompletion& completion) { + auto iter = pending_examples_.find(id); DCHECK(iter != pending_examples_.end()); - iter->second.example.target_value = target_value; - iter->second.example.weight = weight; + iter->second.example.target_value = completion.target_value; + iter->second.example.weight = completion.weight; iter->second.target_done = true; ProcessExampleIfFinished(std::move(iter)); } -void LearningTaskControllerHelper::OnLabelCallbackDestroyed( - int64_t example_id) { - auto iter = pending_examples_.find(example_id); +void LearningTaskControllerHelper::CancelObservation(ObservationId id) { + auto iter = pending_examples_.find(id); // If the example has already been completed, then we shouldn't be called. DCHECK(iter != pending_examples_.end()); @@ -104,11 +66,11 @@ void LearningTaskControllerHelper::OnFeaturesReadyTrampoline( scoped_refptr<base::SequencedTaskRunner> task_runner, base::WeakPtr<LearningTaskControllerHelper> weak_this, - int64_t example_id, + ObservationId id, FeatureVector features) { - auto cb = - base::BindOnce(&LearningTaskControllerHelper::OnFeaturesReady, - std::move(weak_this), example_id, std::move(features)); + // TODO(liberato): this would benefit from promises / deferred data. + auto cb = base::BindOnce(&LearningTaskControllerHelper::OnFeaturesReady, + std::move(weak_this), id, std::move(features)); if (!task_runner->RunsTasksInCurrentSequence()) { task_runner->PostTask(FROM_HERE, std::move(cb)); } else { @@ -116,9 +78,9 @@ } } -void LearningTaskControllerHelper::OnFeaturesReady(int64_t example_id, +void LearningTaskControllerHelper::OnFeaturesReady(ObservationId id, FeatureVector features) { - PendingExampleMap::iterator iter = pending_examples_.find(example_id); + PendingExampleMap::iterator iter = pending_examples_.find(id); // It's possible that OnLabelCallbackDestroyed has already run. That's okay // since we don't support prediction right now. if (iter == pending_examples_.end())
diff --git a/media/learning/impl/learning_task_controller_helper.h b/media/learning/impl/learning_task_controller_helper.h index 0321f242..9370536 100644 --- a/media/learning/impl/learning_task_controller_helper.h +++ b/media/learning/impl/learning_task_controller_helper.h
@@ -21,7 +21,6 @@ namespace learning { class LearningTaskControllerHelperTest; -class RunOnDelete; // Helper class for managing LabelledExamples that are constructed // incrementally. Keeps track of in-flight examples as they're added via @@ -38,6 +37,9 @@ // Callback to add labelled examples as training data. using AddExampleCB = base::RepeatingCallback<void(LabelledExample)>; + // Convenience. + using ObservationId = LearningTaskController::ObservationId; + // TODO(liberato): Consider making the FP not optional. LearningTaskControllerHelper(const LearningTask& task, AddExampleCB add_example_cb, @@ -46,8 +48,10 @@ virtual ~LearningTaskControllerHelper(); // See LearningTaskController::BeginObservation. - LearningTaskController::SetTargetValueCB BeginObservation( - FeatureVector features); + void BeginObservation(ObservationId id, FeatureVector features); + void CompleteObservation(ObservationId id, + const ObservationCompletion& completion); + void CancelObservation(ObservationId id); private: // Record of an example that has been started by RecordObservedFeatures, but @@ -63,32 +67,19 @@ }; // [non-repeating int] = example - using PendingExampleMap = std::map<int64_t, PendingExample>; - - // Called by the SetTargetCB for a particular example. |example_id| is the - // PendingExample id. |run_on_delete| is an RAII class that will notify us - // when it's deleted, so that we can clear the example out of the map. - // |target_value| is the observed target for the example. - // TODO(liberato): This should take a weight, too. - void OnTargetValue(int64_t example_id, - std::unique_ptr<RunOnDelete> run_on_delete, - TargetValue target_value, - WeightType weight); - - // Called when the SetTargetValueCB is destroyed. - void OnLabelCallbackDestroyed(int64_t example_id); + using PendingExampleMap = std::map<ObservationId, PendingExample>; // Called on any sequence when features are ready. Will call OnFeatureReady // if called on |task_runner|, or will post to |task_runner|. static void OnFeaturesReadyTrampoline( scoped_refptr<base::SequencedTaskRunner> task_runner, base::WeakPtr<LearningTaskControllerHelper> weak_this, - int64_t example_id, + ObservationId id, FeatureVector features); // Called when a new feature vector has been finished by |feature_provider_|, // if needed, to actually add the example. - void OnFeaturesReady(int64_t example_id, FeatureVector features); + void OnFeaturesReady(ObservationId example_id, FeatureVector features); // If |example| is finished, then send it to the LearningSession and remove it // from the map. Otherwise, do nothing. @@ -100,9 +91,6 @@ // Optional feature provider. SequenceBoundFeatureProvider feature_provider_; - // Next arbitrary integer to be used in the map. - int64_t next_example_id_ = 1; - // All outstanding PendingExamples. PendingExampleMap pending_examples_;
diff --git a/media/learning/impl/learning_task_controller_helper_unittest.cc b/media/learning/impl/learning_task_controller_helper_unittest.cc index 4e22895..806c43c0 100644 --- a/media/learning/impl/learning_task_controller_helper_unittest.cc +++ b/media/learning/impl/learning_task_controller_helper_unittest.cc
@@ -87,6 +87,8 @@ LearningTask task_; + LearningTaskController::ObservationId id_ = 1; + LabelledExample example_; }; @@ -94,10 +96,10 @@ // A helper that doesn't use a FeatureProvider should forward examples as soon // as they're done. CreateClient(false); - auto cb = helper_->BeginObservation(example_.features); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - EXPECT_TRUE(cb); - std::move(cb).Run(example_.target_value, example_.weight); + helper_->CompleteObservation( + id_, ObservationCompletion(example_.target_value, example_.weight)); EXPECT_TRUE(most_recent_example_); EXPECT_EQ(*most_recent_example_, example_); EXPECT_EQ(most_recent_example_->weight, example_.weight); @@ -107,11 +109,9 @@ TEST_F(LearningTaskControllerHelperTest, DropTargetValueWithoutFPWorks) { // Verify that we can drop an example without labelling it. CreateClient(false); - auto cb = helper_->BeginObservation(example_.features); - EXPECT_TRUE(cb); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - // Drop the callback, which should forget the pending example. - cb.Reset(); + helper_->CancelObservation(id_); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(most_recent_example_); EXPECT_EQ(pending_example_count(), 0u); @@ -120,15 +120,15 @@ TEST_F(LearningTaskControllerHelperTest, AddTargetValueBeforeFP) { // Verify that an example is added if the target value arrives first. CreateClient(true); - auto cb = helper_->BeginObservation(example_.features); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - EXPECT_TRUE(cb); scoped_task_environment_.RunUntilIdle(); // The feature provider should know about the example. EXPECT_EQ(fp_features_, example_.features); // Add the targe value and verify that the example wasn't added yet. - std::move(cb).Run(example_.target_value, example_.weight); + helper_->CompleteObservation( + id_, ObservationCompletion(example_.target_value, example_.weight)); EXPECT_FALSE(most_recent_example_); EXPECT_EQ(pending_example_count(), 1u); @@ -145,15 +145,14 @@ TEST_F(LearningTaskControllerHelperTest, DropTargetValueBeforeFP) { // Verify that an example is correctly dropped before the FP adds features. CreateClient(true); - auto cb = helper_->BeginObservation(example_.features); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - EXPECT_TRUE(cb); scoped_task_environment_.RunUntilIdle(); // The feature provider should know about the example. EXPECT_EQ(fp_features_, example_.features); - // Drop the TargetValue cb. - cb.Reset(); + // Cancel the observation. + helper_->CancelObservation(id_); // We don't care if the example is still queued or not, only that we can // add features and have it be zero by then. @@ -169,9 +168,8 @@ TEST_F(LearningTaskControllerHelperTest, AddTargetValueAfterFP) { // Verify that an example is added if the target value arrives second. CreateClient(true); - auto cb = helper_->BeginObservation(example_.features); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - EXPECT_TRUE(cb); scoped_task_environment_.RunUntilIdle(); // The feature provider should know about the example. EXPECT_EQ(fp_features_, example_.features); @@ -185,7 +183,8 @@ EXPECT_EQ(pending_example_count(), 1u); // Add the targe value and verify that the example is added. - std::move(cb).Run(example_.target_value, example_.weight); + helper_->CompleteObservation( + id_, ObservationCompletion(example_.target_value, example_.weight)); EXPECT_TRUE(most_recent_example_); EXPECT_EQ(*most_recent_example_, example_); EXPECT_EQ(most_recent_example_->weight, example_.weight); @@ -193,11 +192,10 @@ } TEST_F(LearningTaskControllerHelperTest, DropTargetValueAfterFP) { - // Verify that we can drop the TargetValue cb after sending features. + // Verify that we can cancel the observationc after sending features. CreateClient(true); - auto cb = helper_->BeginObservation(example_.features); + helper_->BeginObservation(id_, example_.features); EXPECT_EQ(pending_example_count(), 1u); - EXPECT_TRUE(cb); scoped_task_environment_.RunUntilIdle(); // The feature provider should know about the example. EXPECT_EQ(fp_features_, example_.features); @@ -212,9 +210,9 @@ EXPECT_FALSE(most_recent_example_); EXPECT_EQ(pending_example_count(), 1u); - // Delete the SetTargetValueCB, and verify that the pending example has been + // Cancel the observation, and verify that the pending example has been // removed, and no example was sent to us. - cb.Reset(); + helper_->CancelObservation(id_); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(most_recent_example_); EXPECT_EQ(pending_example_count(), 0u);
diff --git a/media/learning/impl/learning_task_controller_impl.cc b/media/learning/impl/learning_task_controller_impl.cc index a38a633..84092c93 100644 --- a/media/learning/impl/learning_task_controller_impl.cc +++ b/media/learning/impl/learning_task_controller_impl.cc
@@ -38,9 +38,20 @@ LearningTaskControllerImpl::~LearningTaskControllerImpl() = default; -LearningTaskController::SetTargetValueCB -LearningTaskControllerImpl::BeginObservation(const FeatureVector& features) { - return helper_->BeginObservation(features); +void LearningTaskControllerImpl::BeginObservation( + ObservationId id, + const FeatureVector& features) { + helper_->BeginObservation(id, features); +} + +void LearningTaskControllerImpl::CompleteObservation( + ObservationId id, + const ObservationCompletion& completion) { + helper_->CompleteObservation(id, completion); +} + +void LearningTaskControllerImpl::CancelObservation(ObservationId id) { + helper_->CancelObservation(id); } void LearningTaskControllerImpl::AddFinishedExample(LabelledExample example) {
diff --git a/media/learning/impl/learning_task_controller_impl.h b/media/learning/impl/learning_task_controller_impl.h index 74b27897..2866da1 100644 --- a/media/learning/impl/learning_task_controller_impl.h +++ b/media/learning/impl/learning_task_controller_impl.h
@@ -44,7 +44,11 @@ ~LearningTaskControllerImpl() override; // LearningTaskController - SetTargetValueCB BeginObservation(const FeatureVector& features) override; + void BeginObservation(ObservationId id, + const FeatureVector& features) override; + void CompleteObservation(ObservationId id, + const ObservationCompletion& completion) override; + void CancelObservation(ObservationId id) override; private: // Add |example| to the training data, and process it.
diff --git a/media/learning/impl/learning_task_controller_impl_unittest.cc b/media/learning/impl/learning_task_controller_impl_unittest.cc index c9e8a1e..7433919 100644 --- a/media/learning/impl/learning_task_controller_impl_unittest.cc +++ b/media/learning/impl/learning_task_controller_impl_unittest.cc
@@ -113,8 +113,10 @@ } void AddExample(const LabelledExample& example) { - std::move(controller_->BeginObservation(example.features)) - .Run(example.target_value, example.weight); + LearningTaskController::ObservationId id = 1; + controller_->BeginObservation(id, example.features); + controller_->CompleteObservation( + id, ObservationCompletion(example.target_value, example.weight)); } base::test::ScopedTaskEnvironment scoped_task_environment_;
diff --git a/media/mojo/interfaces/interface_factory.mojom b/media/mojo/interfaces/interface_factory.mojom index 4bd229a..86beb52 100644 --- a/media/mojo/interfaces/interface_factory.mojom +++ b/media/mojo/interfaces/interface_factory.mojom
@@ -12,36 +12,12 @@ import "media/mojo/interfaces/video_decoder.mojom"; import "mojo/public/mojom/base/token.mojom"; -// DEPRECATED: This will be cleaned up as part of https://crbug.com/936528. -// It is currently left in to prevent breaking the ChromeCast build, and will -// be removed before M74 branch. -// Defines the types of renderers that can be hosted by a mojo Renderer. -enum HostedRendererType { - // media::DefaultRenderer: Used to offload normal rendering scenarios to a - // different process, for stability or performance reasons. - kDefault, - - // DEPRECATED: Use CreateMediaPlayerRenderer() instead. - [EnableIf=is_android] - kMediaPlayer, - - // DEPRECATED: Use CreateFlingingRenderer() instead. - [EnableIf=is_android] - kFlinging, -}; - // A factory for creating media mojo interfaces. Renderers can only access // ContentDecryptionModules created with the same factory. interface InterfaceFactory { CreateAudioDecoder(AudioDecoder& audio_decoder); CreateVideoDecoder(VideoDecoder& video_decoder); - // DEPRECATED: This will be cleaned up as part of https://crbug.com/936528. - // It is currently left in to prevent breaking the ChromeCast build, and will - // be removed before M74 branch. - CreateRenderer(HostedRendererType type, string audio_device_id, - Renderer& renderer); - // Creates a regular media::Renderer (DefaultRendererFactory). CreateDefaultRenderer(string audio_device_id, Renderer& renderer);
diff --git a/media/mojo/services/interface_factory_impl.cc b/media/mojo/services/interface_factory_impl.cc index 8e5bf0b..f4353b1 100644 --- a/media/mojo/services/interface_factory_impl.cc +++ b/media/mojo/services/interface_factory_impl.cc
@@ -95,15 +95,6 @@ #endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER) } -// TODO(https://crbug.com/936528) : remove this method. -void InterfaceFactoryImpl::CreateRenderer( - mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) { - DCHECK_EQ(type, mojom::HostedRendererType::kDefault); - CreateDefaultRenderer(audio_device_id, std::move(renderer)); -} - void InterfaceFactoryImpl::CreateDefaultRenderer( const std::string& audio_device_id, mojo::InterfaceRequest<mojom::Renderer> request) {
diff --git a/media/mojo/services/interface_factory_impl.h b/media/mojo/services/interface_factory_impl.h index 5e91daf..06e7672 100644 --- a/media/mojo/services/interface_factory_impl.h +++ b/media/mojo/services/interface_factory_impl.h
@@ -42,10 +42,6 @@ void CreateVideoDecoder(mojom::VideoDecoderRequest request) final; void CreateDefaultRenderer(const std::string& audio_device_id, mojom::RendererRequest request) final; - // TODO(https://crbug.com/936528) : remove this method. - void CreateRenderer(mojom::HostedRendererType type, - const std::string& audio_device_id, - media::mojom::RendererRequest renderer) final; #if defined(OS_ANDROID) void CreateMediaPlayerRenderer(mojom::RendererRequest request) final; void CreateFlingingRenderer(const std::string& presentation_id,
diff --git a/media/video/gpu_video_accelerator_factories.h b/media/video/gpu_video_accelerator_factories.h index 8825417..1f0cb303 100644 --- a/media/video/gpu_video_accelerator_factories.h +++ b/media/video/gpu_video_accelerator_factories.h
@@ -89,8 +89,7 @@ virtual std::unique_ptr<media::VideoDecoder> CreateVideoDecoder( MediaLog* media_log, - const RequestOverlayInfoCB& request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) = 0; + const RequestOverlayInfoCB& request_overlay_info_cb) = 0; // Caller owns returned pointer, but should call Destroy() on it (instead of // directly deleting) for proper destruction, as per the
diff --git a/media/video/mock_gpu_video_accelerator_factories.h b/media/video/mock_gpu_video_accelerator_factories.h index 5c8d3fc..1c8850d 100644 --- a/media/video/mock_gpu_video_accelerator_factories.h +++ b/media/video/mock_gpu_video_accelerator_factories.h
@@ -37,10 +37,10 @@ MOCK_METHOD0(GetCommandBufferRouteId, int32_t()); MOCK_METHOD1(IsDecoderConfigSupported, bool(const VideoDecoderConfig&)); - MOCK_METHOD3(CreateVideoDecoder, - std::unique_ptr<media::VideoDecoder>(MediaLog*, - const RequestOverlayInfoCB&, - const gfx::ColorSpace&)); + MOCK_METHOD2( + CreateVideoDecoder, + std::unique_ptr<media::VideoDecoder>(MediaLog*, + const RequestOverlayInfoCB&)); // CreateVideo{Decode,Encode}Accelerator returns scoped_ptr, which the mocking // framework does not want. Trampoline them.
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn index 4f58b83..13093151 100644 --- a/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -488,8 +488,22 @@ # These could probably be merged with "test_interfaces" at some point. mojom("other_test_interfaces") { testonly = true - cpp_only = true sources = [ "new_endpoint_types.test-mojom", ] } + +# Ensure that some target forces JS and Java bindings generation when all +# targets are built. This provides a basic generation smoke test for new +# endpoint types in mojom. +group("test_generation") { + testonly = true + deps = [ + ":other_test_interfaces", + ":other_test_interfaces_js", + ] + + if (is_android) { + deps += [ ":other_test_interfaces_java" ] + } +}
diff --git a/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl index a91260e..e8a7460 100644 --- a/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl
@@ -95,10 +95,12 @@ {%- endmacro -%} {%- macro generate_or_mutate_interface(obj, operation, kind, name) -%} -{%- if kind|is_interface_request_kind -%} +{%- if kind|is_interface_request_kind or kind|is_pending_receiver_kind -%} {{build_call(obj, operation, 'InterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}} {%- elif kind|is_interface_kind -%} {{build_call(obj, operation, 'Interface', name, '"' ~ kind.module.namespace ~ '.' ~ kind.name ~ '"', kind.is_nullable|to_js_boolean)}} +{%- elif kind|is_pending_remote_kind -%} +{{build_call(obj, operation, 'Interface', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}} {%- elif kind|is_associated_interface_request_kind -%} {{build_call(obj, operation, 'AssociatedInterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}} {%- elif kind|is_associated_interface_kind -%}
diff --git a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl index 0e9b8931..de19055 100644 --- a/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl +++ b/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl
@@ -20,11 +20,12 @@ // validate {{name}} err = messageValidator.validateMapPointer({{offset}}, {{field|validate_map_params}}); {{_check_err()}} -{%- elif field.kind|is_interface_kind %} +{%- elif field.kind|is_interface_kind or field.kind|is_pending_remote_kind %} // validate {{name}} err = messageValidator.validateInterface({{offset}}, {{field|validate_nullable_params}}); {{_check_err()}} -{%- elif field.kind|is_interface_request_kind %} +{%- elif field.kind|is_interface_request_kind or + field.kind|is_pending_receiver_kind %} // validate {{name}} err = messageValidator.validateInterfaceRequest({{offset}}, {{field|validate_nullable_params}}) {{_check_err()}}
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py index 0f2b618..8097af3 100644 --- a/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -134,7 +134,9 @@ if name in _java_reserved_types: return name + '_' return name - if mojom.IsInterfaceRequestKind(element) or mojom.IsAssociatedKind(element): + if (mojom.IsInterfaceRequestKind(element) or + mojom.IsAssociatedKind(element) or mojom.IsPendingRemoteKind(element) or + mojom.IsPendingReceiverKind(element)): return GetNameForElement(element.kind) if isinstance(element, (mojom.Method, mojom.Parameter, @@ -199,8 +201,12 @@ params.append(GetArrayExpectedLength(kind)) if mojom.IsInterfaceKind(kind): params.append('%s.MANAGER' % GetJavaType(context, kind)) + if mojom.IsPendingRemoteKind(kind): + params.append('%s.MANAGER' % GetJavaType(context, kind.kind)) if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind): params.append('%s.MANAGER' % GetJavaType(context, kind.kind)) + if mojom.IsArrayKind(kind) and mojom.IsPendingRemoteKind(kind.kind): + params.append('%s.MANAGER' % GetJavaType(context, kind.kind.kind)) return params @@ -211,9 +217,9 @@ return _DecodeMethodName(kind.kind) + 's' if mojom.IsEnumKind(kind): return _DecodeMethodName(mojom.INT32) - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return 'readInterfaceRequest' - if mojom.IsInterfaceKind(kind): + if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind): return 'readServiceInterface' if mojom.IsAssociatedInterfaceRequestKind(kind): return 'readAssociatedInterfaceRequestNotSupported' @@ -271,7 +277,9 @@ mojom.IsInterfaceKind(kind) or mojom.IsUnionKind(kind)): return GetNameForKind(context, kind) - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsPendingRemoteKind(kind): + return GetNameForKind(context, kind.kind) + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' % GetNameForKind(context, kind.kind)) if mojom.IsAssociatedInterfaceKind(kind):
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py index 9eb5f2d..bc8bc63 100644 --- a/mojo/public/tools/bindings/generators/mojom_js_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -289,7 +289,9 @@ "is_any_handle_kind": mojom.IsAnyHandleKind, "is_any_interface_kind": mojom.IsAnyInterfaceKind, "is_interface_kind": mojom.IsInterfaceKind, + "is_pending_remote_kind": mojom.IsPendingRemoteKind, "is_interface_request_kind": mojom.IsInterfaceRequestKind, + "is_pending_receiver_kind": mojom.IsPendingReceiverKind, "is_map_kind": mojom.IsMapKind, "is_object_kind": mojom.IsObjectKind, "is_reference_kind": mojom.IsReferenceKind, @@ -381,6 +383,8 @@ return _kind_to_closure_type[kind] if mojom.IsInterfaceKind(kind): return kind.module.namespace + "." + kind.name + "Ptr" + if mojom.IsPendingRemoteKind(kind): + return kind.kind.module.namespace + "." + kind.kind.name + "Ptr" if (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)): return kind.module.namespace + "." + kind.name @@ -392,7 +396,7 @@ if mojom.IsMapKind(kind): return "Map<%s, %s>" % ( self._ClosureType(kind.key_kind), self._ClosureType(kind.value_kind)) - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return "mojo.InterfaceRequest" # TODO(calamity): Support associated interfaces properly. if mojom.IsAssociatedInterfaceKind(kind): @@ -426,7 +430,8 @@ self._LiteClosureTypeWithNullability(kind.key_kind), self._LiteClosureTypeWithNullability(kind.value_kind)) - if mojom.IsAssociatedKind(kind) or mojom.IsInterfaceRequestKind(kind): + if (mojom.IsAssociatedKind(kind) or mojom.IsInterfaceRequestKind(kind) or + mojom.IsPendingRemoteKind(kind) or mojom.IsPendingReceiverKind(kind)): named_kind = kind.kind else: named_kind = kind @@ -442,9 +447,9 @@ if (mojom.IsStructKind(kind) or mojom.IsUnionKind(kind) or mojom.IsEnumKind(kind)): return name - if mojom.IsInterfaceKind(kind): + if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind): return name + "Proxy" - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return name + "Request" # TODO(calamity): Support associated interfaces properly. if mojom.IsAssociatedInterfaceKind(kind): @@ -517,7 +522,8 @@ self._LiteJavaScriptType(kind.value_kind), "true" if mojom.IsNullableKind(kind.value_kind) else "false") - if mojom.IsAssociatedKind(kind) or mojom.IsInterfaceRequestKind(kind): + if (mojom.IsAssociatedKind(kind) or mojom.IsInterfaceRequestKind(kind) or + mojom.IsPendingRemoteKind(kind) or mojom.IsPendingReceiverKind(kind)): named_kind = kind.kind else: named_kind = kind @@ -533,9 +539,9 @@ if (mojom.IsStructKind(kind) or mojom.IsUnionKind(kind) or mojom.IsEnumKind(kind)): return "%sSpec.$" % name - if mojom.IsInterfaceKind(kind): + if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind): return "mojo.internal.InterfaceProxy(%sProxy)" % name - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return "mojo.internal.InterfaceRequest(%sRequest)" % name if mojom.IsAssociatedInterfaceKind(kind): # TODO(rockot): Implement associated interfaces. @@ -564,7 +570,10 @@ return "null" if mojom.IsInterfaceKind(field.kind): return "new %sPtr()" % self._JavaScriptType(field.kind) - if mojom.IsInterfaceRequestKind(field.kind): + if mojom.IsPendingRemoteKind(field.kind): + return "new %sPtr()" % self._JavaScriptType(field.kind.kind) + if (mojom.IsInterfaceRequestKind(field.kind) or + mojom.IsPendingReceiverKind(field.kind)): return "new bindings.InterfaceRequest()" if mojom.IsAssociatedInterfaceKind(field.kind): return "new associatedBindings.AssociatedInterfacePtrInfo()" @@ -605,7 +614,11 @@ return "new codec.%s(%sPtr)" % ( "NullableInterface" if mojom.IsNullableKind(kind) else "Interface", self._JavaScriptType(kind)) - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsPendingRemoteKind(kind): + return "new codec.%s(%sPtr)" % ( + "NullableInterface" if mojom.IsNullableKind(kind) else "Interface", + self._JavaScriptType(kind.kind)) + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return "codec.%s" % ( "NullableInterfaceRequest" if mojom.IsNullableKind(kind) else "InterfaceRequest") @@ -771,12 +784,15 @@ return result def _FuzzHandleName(self, kind): - if mojom.IsInterfaceRequestKind(kind): + if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): return '{0}.{1}Request'.format(kind.kind.module.namespace, kind.kind.name) elif mojom.IsInterfaceKind(kind): return '{0}.{1}Ptr'.format(kind.module.namespace, kind.name) + elif mojom.IsPendingRemoteKind(kind): + return '{0}.{1}Ptr'.format(kind.kind.module.namespace, + kind.kind.name) elif mojom.IsAssociatedInterfaceRequestKind(kind): return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace, kind.kind.name)
diff --git a/net/BUILD.gn b/net/BUILD.gn index 6838a451..ac6024ea 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -3061,6 +3061,7 @@ "third_party/quic/core/quic_epoll_connection_helper.h", "third_party/quic/core/quic_packet_reader.cc", "third_party/quic/core/quic_packet_reader.h", + "third_party/quic/platform/api/quic_default_buffer_allocator.h", "third_party/quic/platform/api/quic_default_proof_providers.h", "third_party/quic/platform/api/quic_system_event_loop.h", "third_party/quic/platform/impl/batch_writer/quic_batch_writer_base.cc", @@ -3071,6 +3072,7 @@ "third_party/quic/platform/impl/batch_writer/quic_gso_batch_writer.h", "third_party/quic/platform/impl/batch_writer/quic_sendmmsg_batch_writer.cc", "third_party/quic/platform/impl/batch_writer/quic_sendmmsg_batch_writer.h", + "third_party/quic/platform/impl/quic_default_buffer_allocator_impl.h", "third_party/quic/platform/impl/quic_default_proof_providers_impl.cc", "third_party/quic/platform/impl/quic_default_proof_providers_impl.h", "third_party/quic/platform/impl/quic_epoll_clock.cc", @@ -3343,8 +3345,6 @@ sources += [ "third_party/quic/test_tools/bad_packet_writer.cc", "third_party/quic/test_tools/bad_packet_writer.h", - "third_party/quic/test_tools/fake_epoll_server.cc", - "third_party/quic/test_tools/fake_epoll_server.h", "third_party/quic/test_tools/limited_mtu_test_writer.cc", "third_party/quic/test_tools/limited_mtu_test_writer.h", "third_party/quic/test_tools/packet_dropping_test_writer.cc", @@ -3361,6 +3361,8 @@ "third_party/quic/test_tools/quic_test_server.h", "third_party/quic/test_tools/server_thread.cc", "third_party/quic/test_tools/server_thread.h", + "tools/epoll_server/fake_epoll_server.cc", + "tools/epoll_server/fake_epoll_server.h", ] deps += [ ":epoll_quic_tools",
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn index 989877f..0e71ba1 100644 --- a/net/dns/BUILD.gn +++ b/net/dns/BUILD.gn
@@ -31,6 +31,8 @@ sources += [ "address_sorter.h", "address_sorter_win.cc", + "context_host_resolver.cc", + "context_host_resolver.h", "dns_config.cc", "dns_config_overrides.cc", "dns_config_service.cc", @@ -433,8 +435,8 @@ source_set("fuzzer_test_support") { testonly = true sources = [ - "fuzzed_host_resolver.cc", - "fuzzed_host_resolver.h", + "fuzzed_context_host_resolver.cc", + "fuzzed_context_host_resolver.h", ] deps = [ "//base",
diff --git a/net/dns/context_host_resolver.cc b/net/dns/context_host_resolver.cc new file mode 100644 index 0000000..f7b74aa7 --- /dev/null +++ b/net/dns/context_host_resolver.cc
@@ -0,0 +1,107 @@ +// Copyright (c) 2019 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/dns/context_host_resolver.h" + +#include <utility> + +#include "base/strings/string_piece.h" +#include "base/time/tick_clock.h" +#include "net/dns/dns_client.h" +#include "net/dns/dns_config.h" +#include "net/dns/host_resolver_impl.h" +#include "net/dns/host_resolver_proc.h" + +namespace net { + +ContextHostResolver::ContextHostResolver(std::unique_ptr<HostResolverImpl> impl) + : impl_(std::move(impl)) {} + +ContextHostResolver::~ContextHostResolver() = default; + +std::unique_ptr<HostResolver::ResolveHostRequest> +ContextHostResolver::CreateRequest( + const HostPortPair& host, + const NetLogWithSource& source_net_log, + const base::Optional<ResolveHostParameters>& optional_parameters) { + return impl_->CreateRequest(host, source_net_log, optional_parameters); +} + +std::unique_ptr<HostResolver::MdnsListener> +ContextHostResolver::CreateMdnsListener(const HostPortPair& host, + DnsQueryType query_type) { + return impl_->CreateMdnsListener(host, query_type); +} + +void ContextHostResolver::SetDnsClientEnabled(bool enabled) { + impl_->SetDnsClientEnabled(enabled); +} + +HostCache* ContextHostResolver::GetHostCache() { + return impl_->GetHostCache(); +} + +bool ContextHostResolver::HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out, + bool* secure_out) const { + return impl_->HasCached(hostname, source_out, stale_out, secure_out); +} + +std::unique_ptr<base::Value> ContextHostResolver::GetDnsConfigAsValue() const { + return impl_->GetDnsConfigAsValue(); +} + +void ContextHostResolver::SetNoIPv6OnWifi(bool no_ipv6_on_wifi) { + impl_->SetNoIPv6OnWifi(no_ipv6_on_wifi); +} + +bool ContextHostResolver::GetNoIPv6OnWifi() { + return impl_->GetNoIPv6OnWifi(); +} + +void ContextHostResolver::SetDnsConfigOverrides( + const DnsConfigOverrides& overrides) { + impl_->SetDnsConfigOverrides(overrides); +} + +void ContextHostResolver::SetRequestContext( + URLRequestContext* request_context) { + impl_->SetRequestContext(request_context); +} + +const std::vector<DnsConfig::DnsOverHttpsServerConfig>* +ContextHostResolver::GetDnsOverHttpsServersForTesting() const { + return impl_->GetDnsOverHttpsServersForTesting(); +} + +size_t ContextHostResolver::LastRestoredCacheSize() const { + return impl_->LastRestoredCacheSize(); +} + +size_t ContextHostResolver::CacheSize() const { + return impl_->CacheSize(); +} + +void ContextHostResolver::SetProcParamsForTesting( + const ProcTaskParams& proc_params) { + impl_->set_proc_params_for_test(proc_params); +} + +void ContextHostResolver::SetDnsClientForTesting( + std::unique_ptr<DnsClient> dns_client) { + impl_->SetDnsClient(std::move(dns_client)); +} + +void ContextHostResolver::SetBaseDnsConfigForTesting( + const DnsConfig& base_config) { + impl_->SetBaseDnsConfigForTesting(base_config); +} + +void ContextHostResolver::SetTickClockForTesting( + const base::TickClock* tick_clock) { + impl_->SetTickClockForTesting(tick_clock); +} + +} // namespace net
diff --git a/net/dns/context_host_resolver.h b/net/dns/context_host_resolver.h new file mode 100644 index 0000000..c200ded --- /dev/null +++ b/net/dns/context_host_resolver.h
@@ -0,0 +1,82 @@ +// Copyright (c) 2019 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 NET_DNS_CONTEXT_HOST_RESOLVER_H_ +#define NET_DNS_CONTEXT_HOST_RESOLVER_H_ + +#include <memory> +#include <vector> + +#include "net/base/net_export.h" +#include "net/dns/host_resolver.h" + +namespace base { +class TickClock; +} // namespace base + +namespace net { + +class DnsClient; +struct DnsConfig; +class HostResolverImpl; +struct ProcTaskParams; + +// Wrapper for HostResolverImpl that sets per-context parameters for created +// requests. Except for tests, typically only interacted with through the +// HostResolver interface. +// +// See HostResolver::Create[...]() methods for construction. +// +// TODO(crbug.com/934402): Construct individually for each URLRequestContext +// rather than using this as the singleton shared resolver. +class NET_EXPORT ContextHostResolver : public HostResolver { + public: + // Creates a ContextHostResolver that forwards all of its requests through + // |impl|. + explicit ContextHostResolver(std::unique_ptr<HostResolverImpl> impl); + ~ContextHostResolver() override; + + // HostResolver methods: + std::unique_ptr<ResolveHostRequest> CreateRequest( + const HostPortPair& host, + const NetLogWithSource& net_log, + const base::Optional<ResolveHostParameters>& optional_parameters) + override; + std::unique_ptr<MdnsListener> CreateMdnsListener( + const HostPortPair& host, + DnsQueryType query_type) override; + void SetDnsClientEnabled(bool enabled) override; + HostCache* GetHostCache() override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out, + bool* secure_out) const override; + std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; + void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override; + bool GetNoIPv6OnWifi() override; + void SetDnsConfigOverrides(const DnsConfigOverrides& overrides) override; + void SetRequestContext(URLRequestContext* request_context) override; + const std::vector<DnsConfig::DnsOverHttpsServerConfig>* + GetDnsOverHttpsServersForTesting() const override; + + // Returns the number of host cache entries that were restored, or 0 if there + // is no cache. + size_t LastRestoredCacheSize() const; + // Returns the number of entries in the host cache, or 0 if there is no cache. + size_t CacheSize() const; + + void SetProcParamsForTesting(const ProcTaskParams& proc_params); + void SetDnsClientForTesting(std::unique_ptr<DnsClient> dns_client); + void SetBaseDnsConfigForTesting(const DnsConfig& base_config); + void SetTickClockForTesting(const base::TickClock* tick_clock); + + private: + // TODO(crbug.com/934402): Make this a non-owned pointer to the singleton + // resolver. + std::unique_ptr<HostResolverImpl> impl_; +}; + +} // namespace net + +#endif // NET_DNS_CONTEXT_HOST_RESOLVER_H_
diff --git a/net/dns/fuzzed_host_resolver.cc b/net/dns/fuzzed_context_host_resolver.cc similarity index 84% rename from net/dns/fuzzed_host_resolver.cc rename to net/dns/fuzzed_context_host_resolver.cc index 702bff01..933f626 100644 --- a/net/dns/fuzzed_host_resolver.cc +++ b/net/dns/fuzzed_context_host_resolver.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 "net/dns/fuzzed_host_resolver.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include <stdint.h> #include <algorithm> @@ -29,8 +29,11 @@ #include "net/dns/dns_client.h" #include "net/dns/dns_config.h" #include "net/dns/dns_hosts.h" +#include "net/dns/host_resolver_impl.h" +#include "net/dns/host_resolver_proc.h" #include "net/dns/mdns_client.h" #include "net/dns/public/util.h" +#include "net/log/net_log.h" #include "net/log/net_log_with_source.h" #include "net/socket/datagram_server_socket.h" @@ -294,33 +297,69 @@ base::FuzzedDataProvider* const data_provider_; }; +class FuzzedHostResolverImpl : public HostResolverImpl { + public: + // |data_provider| and |net_log| must outlive the FuzzedHostResolver. + FuzzedHostResolverImpl(const Options& options, + NetLog* net_log, + base::FuzzedDataProvider* data_provider) + : HostResolverImpl(options, net_log), + data_provider_(data_provider), + is_ipv6_reachable_(data_provider->ConsumeBool()), + data_provider_weak_factory_(data_provider) { + ProcTaskParams proc_task_params( + new FuzzedHostResolverProc(data_provider_weak_factory_.GetWeakPtr()), + // Retries are only used when the original request hangs, which this + // class currently can't simulate. + 0 /* max_retry_attempts */); + set_proc_params_for_test(proc_task_params); + SetTaskRunnerForTesting(base::SequencedTaskRunnerHandle::Get()); + SetMdnsSocketFactoryForTesting( + std::make_unique<FuzzedMdnsSocketFactory>(data_provider_)); + } + + ~FuzzedHostResolverImpl() override = default; + + private: + // HostResolverImpl implementation: + bool IsGloballyReachable(const IPAddress& dest, + const NetLogWithSource& net_log) override { + return is_ipv6_reachable_; + } + + void RunLoopbackProbeJob() override { + SetHaveOnlyLoopbackAddresses(data_provider_->ConsumeBool()); + } + + base::FuzzedDataProvider* const data_provider_; + + // Fixed value to be returned by IsIPv6Reachable. + const bool is_ipv6_reachable_; + + base::WeakPtrFactory<base::FuzzedDataProvider> data_provider_weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(FuzzedHostResolverImpl); +}; + } // namespace -FuzzedHostResolver::FuzzedHostResolver(const Options& options, - NetLog* net_log, - base::FuzzedDataProvider* data_provider) - : HostResolverImpl(options, net_log), +FuzzedContextHostResolver::FuzzedContextHostResolver( + const Options& options, + NetLog* net_log, + base::FuzzedDataProvider* data_provider) + : ContextHostResolver( + std::make_unique<FuzzedHostResolverImpl>(options, + net_log, + data_provider)), data_provider_(data_provider), socket_factory_(data_provider), - is_ipv6_reachable_(data_provider->ConsumeBool()), - net_log_(net_log), - data_provider_weak_factory_(data_provider) { - HostResolverImpl::ProcTaskParams proc_task_params( - new FuzzedHostResolverProc(data_provider_weak_factory_.GetWeakPtr()), - // Retries are only used when the original request hangs, which this class - // currently can't simulate. - 0 /* max_retry_attempts */); - set_proc_params_for_test(proc_task_params); - SetTaskRunnerForTesting(base::SequencedTaskRunnerHandle::Get()); - SetMdnsSocketFactoryForTesting( - std::make_unique<FuzzedMdnsSocketFactory>(data_provider_)); -} + net_log_(net_log) {} -FuzzedHostResolver::~FuzzedHostResolver() = default; +FuzzedContextHostResolver::~FuzzedContextHostResolver() = default; -void FuzzedHostResolver::SetDnsClientEnabled(bool enabled) { +void FuzzedContextHostResolver::SetDnsClientEnabled(bool enabled) { if (!enabled) { - HostResolverImpl::SetDnsClientEnabled(false); + ContextHostResolver::SetDnsClientEnabled(false); return; } @@ -382,16 +421,7 @@ base::Bind(&base::FuzzedDataProvider::ConsumeIntegralInRange<int32_t>, base::Unretained(data_provider_))); dns_client->SetConfig(config); - SetDnsClient(std::move(dns_client)); -} - -bool FuzzedHostResolver::IsGloballyReachable(const IPAddress& dest, - const NetLogWithSource& net_log) { - return is_ipv6_reachable_; -} - -void FuzzedHostResolver::RunLoopbackProbeJob() { - SetHaveOnlyLoopbackAddresses(data_provider_->ConsumeBool()); + SetDnsClientForTesting(std::move(dns_client)); } } // namespace net
diff --git a/net/dns/fuzzed_context_host_resolver.h b/net/dns/fuzzed_context_host_resolver.h new file mode 100644 index 0000000..26bad94a --- /dev/null +++ b/net/dns/fuzzed_context_host_resolver.h
@@ -0,0 +1,66 @@ +// 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 NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_ +#define NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/macros.h" +#include "net/dns/context_host_resolver.h" +#include "net/dns/host_resolver.h" +#include "net/socket/fuzzed_socket_factory.h" + +namespace base { +class FuzzedDataProvider; +} + +namespace net { + +class NetLog; + +// HostResolver that uses a fuzzer to determine what results to return. It +// inherits from ContextHostResolver, unlike MockHostResolver, so more closely +// matches real behavior. +// +// By default uses a mocked out system resolver, though can be configured to +// use the built-in async resolver (Built in DNS stub resolver) with a fuzzed +// set of UDP/TCP sockets. +// +// To make behavior most deterministic, does not use the WorkerPool to run its +// simulated platform host resolver calls, instead runs them on the thread it is +// created on. +// +// Note that it does not attempt to sort the resulting AddressList when using +// the mock system resolver path. +// +// The async DNS client can make system calls in AddressSorterPosix, but other +// methods that make system calls are stubbed out. +class FuzzedContextHostResolver : public ContextHostResolver { + public: + FuzzedContextHostResolver(const Options& options, + NetLog* net_log, + base::FuzzedDataProvider* data_provider); + ~FuzzedContextHostResolver() override; + + // Enable / disable the async resolver. When enabled, installs a + // DnsClient with fuzzed UDP and TCP sockets. + void SetDnsClientEnabled(bool enabled) override; + + private: + base::FuzzedDataProvider* const data_provider_; + + // Used for UDP and TCP sockets if the async resolver is enabled. + FuzzedSocketFactory socket_factory_; + + NetLog* const net_log_; + + DISALLOW_COPY_AND_ASSIGN(FuzzedContextHostResolver); +}; + +} // namespace net + +#endif // NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_
diff --git a/net/dns/fuzzed_host_resolver.h b/net/dns/fuzzed_host_resolver.h deleted file mode 100644 index 7cb1b51..0000000 --- a/net/dns/fuzzed_host_resolver.h +++ /dev/null
@@ -1,82 +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. - -#ifndef NET_DNS_FUZZED_HOST_RESOLVER_H_ -#define NET_DNS_FUZZED_HOST_RESOLVER_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "net/base/address_family.h" -#include "net/dns/host_resolver.h" -#include "net/dns/host_resolver_impl.h" -#include "net/socket/fuzzed_socket_factory.h" - -namespace base { -class FuzzedDataProvider; -} - -namespace net { - -class AddressList; -class DnsClient; -class NetLog; - -// HostResolver that uses a fuzzer to determine what results to return. It -// inherits from HostResolverImpl, unlike MockHostResolver, so more closely -// matches real behavior. -// -// By default uses a mocked out system resolver, though can be configured to -// use the built-in async resolver (Built in DNS stub resolver) with a fuzzed -// set of UDP/TCP sockets. -// -// To make behavior most deterministic, does not use the WorkerPool to run its -// simulated platform host resolver calls, instead runs them on the thread it is -// created on. -// -// Note that it does not attempt to sort the resulting AddressList when using -// the mock system resolver path. -// -// The async DNS client can make system calls in AddressSorterPosix, but other -// methods that make system calls are stubbed out. -class FuzzedHostResolver : public HostResolverImpl { - public: - // |data_provider| and |net_log| must outlive the FuzzedHostResolver. - FuzzedHostResolver(const Options& options, - NetLog* net_log, - base::FuzzedDataProvider* data_provider); - ~FuzzedHostResolver() override; - - // Enable / disable the async resolver. When enabled, installs a - // DnsClient with fuzzed UDP and TCP sockets. Overrides - // HostResolverImpl method of the same name. - void SetDnsClientEnabled(bool enabled) override; - - private: - // HostResolverImpl implementation: - bool IsGloballyReachable(const IPAddress& dest, - const NetLogWithSource& net_log) override; - void RunLoopbackProbeJob() override; - - base::FuzzedDataProvider* data_provider_; - - // Used for UDP and TCP sockets if the async resolver is enabled. - FuzzedSocketFactory socket_factory_; - - // Fixed value to be returned by IsIPv6Reachable. - const bool is_ipv6_reachable_; - - NetLog* net_log_; - - base::WeakPtrFactory<base::FuzzedDataProvider> data_provider_weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(FuzzedHostResolver); -}; - -} // namespace net - -#endif // NET_DNS_FUZZED_HOST_RESOLVER_H_
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc index 5313e96..2f13cc4 100644 --- a/net/dns/host_resolver.cc +++ b/net/dns/host_resolver.cc
@@ -15,6 +15,7 @@ #include "base/values.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_client.h" #include "net/dns/dns_util.h" #include "net/dns/host_cache.h" @@ -144,15 +145,15 @@ std::unique_ptr<HostResolver> HostResolver::CreateSystemResolver( const Options& options, NetLog* net_log) { - return std::unique_ptr<HostResolver>( - CreateSystemResolverImpl(options, net_log).release()); + return CreateSystemResolverImpl(options, net_log); } // static -std::unique_ptr<HostResolverImpl> HostResolver::CreateSystemResolverImpl( +std::unique_ptr<ContextHostResolver> HostResolver::CreateSystemResolverImpl( const Options& options, NetLog* net_log) { - return std::make_unique<HostResolverImpl>(options, net_log); + return std::make_unique<ContextHostResolver>( + std::make_unique<HostResolverImpl>(options, net_log)); } // static @@ -162,7 +163,7 @@ } // static -std::unique_ptr<HostResolverImpl> HostResolver::CreateDefaultResolverImpl( +std::unique_ptr<ContextHostResolver> HostResolver::CreateDefaultResolverImpl( NetLog* net_log) { return CreateSystemResolverImpl(Options(), net_log); }
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index 72a1f8a..7fd5cef 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -30,22 +30,21 @@ namespace net { class AddressList; +class ContextHostResolver; class DnsClient; struct DnsConfigOverrides; -class HostResolverImpl; class NetLog; class NetLogWithSource; class URLRequestContext; // This class represents the task of resolving hostnames (or IP address -// literal) to an AddressList object. +// literal) to an AddressList object (or other DNS-style results). // -// HostResolver can handle multiple requests at a time, so when cancelling a -// request the RequestHandle that was returned by Resolve() needs to be -// given. A simpler alternative for consumers that only have 1 outstanding -// request at a time is to create a SingleRequestHostResolver wrapper around -// HostResolver (which will automatically cancel the single request when it -// goes out of scope). +// Typically implemented by ContextHostResolver or wrappers thereof. See +// HostResolver::Create[...]() methods for construction or URLRequestContext for +// retrieval. +// +// See mock_host_resolver.h for test implementations. class NET_EXPORT HostResolver { public: // Handler for an individual host resolution request. Created by @@ -284,6 +283,8 @@ // read from the system for DnsClient resolution. virtual void SetDnsConfigOverrides(const DnsConfigOverrides& overrides); + // Sets the URLRequestContext to be used for underlying requests made at the + // HTTP level (e.g. DNS over HTTPS requests). virtual void SetRequestContext(URLRequestContext* request_context) {} // Returns the currently configured DNS over HTTPS servers. Returns nullptr if @@ -297,27 +298,27 @@ static std::unique_ptr<HostResolver> CreateSystemResolver( const Options& options, NetLog* net_log); - // Same, but explicitly returns the HostResolverImpl. Only used by - // StaleHostResolver in cronet. - static std::unique_ptr<HostResolverImpl> CreateSystemResolverImpl( + // Same, but explicitly returns the implementing ContextHostResolver. Only + // used by tests. + static std::unique_ptr<ContextHostResolver> CreateSystemResolverImpl( const Options& options, NetLog* net_log); // As above, but uses default parameters. static std::unique_ptr<HostResolver> CreateDefaultResolver(NetLog* net_log); - // Same, but explicitly returns the HostResolverImpl. Only used by - // StaleHostResolver in cronet. - static std::unique_ptr<HostResolverImpl> CreateDefaultResolverImpl( + // Same, but explicitly returns the implementing ContextHostResolver. Only + // used by tests and by StaleHostResolver in Cronet. + static std::unique_ptr<ContextHostResolver> CreateDefaultResolverImpl( NetLog* net_log); - protected: - HostResolver(); - // Helpers for interacting with HostCache and ProcResolver. static AddressFamily DnsQueryTypeToAddressFamily(DnsQueryType query_type); static HostResolverFlags ParametersToHostResolverFlags( const ResolveHostParameters& parameters); + protected: + HostResolver(); + private: DISALLOW_COPY_AND_ASSIGN(HostResolver); };
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc index d0c75fa..7e95f8c6 100644 --- a/net/dns/host_resolver_impl.cc +++ b/net/dns/host_resolver_impl.cc
@@ -100,10 +100,6 @@ namespace { -// Default delay between calls to the system resolver for the same hostname. -// (Can be overridden by field trial.) -const int64_t kDnsDefaultUnresponsiveDelayMs = 6000; - // Limit the size of hostnames that will be resolved to combat issues in // some platform's resolvers. const size_t kMaxHostLength = 4096; @@ -509,7 +505,8 @@ request_host_(request_host), parameters_(optional_parameters ? optional_parameters.value() : ResolveHostParameters()), - host_resolver_flags_(ParametersToHostResolverFlags(parameters_)), + host_resolver_flags_( + HostResolver::ParametersToHostResolverFlags(parameters_)), priority_(parameters_.initial_priority), job_(nullptr), resolver_(resolver), @@ -791,7 +788,8 @@ AddressList results; int os_error = 0; int error = resolver_proc->Resolve( - key.hostname, DnsQueryTypeToAddressFamily(key.dns_query_type), + key.hostname, + HostResolver::DnsQueryTypeToAddressFamily(key.dns_query_type), key.host_resolver_flags, &results, &os_error); network_task_runner->PostTask( @@ -2124,25 +2122,6 @@ //----------------------------------------------------------------------------- -HostResolverImpl::ProcTaskParams::ProcTaskParams( - HostResolverProc* resolver_proc, - size_t max_retry_attempts) - : resolver_proc(resolver_proc), - max_retry_attempts(max_retry_attempts), - unresponsive_delay( - base::TimeDelta::FromMilliseconds(kDnsDefaultUnresponsiveDelayMs)), - retry_factor(2) { - // Maximum of 4 retry attempts for host resolution. - static const size_t kDefaultMaxRetryAttempts = 4u; - if (max_retry_attempts == HostResolver::kDefaultRetryAttempts) - max_retry_attempts = kDefaultMaxRetryAttempts; -} - -HostResolverImpl::ProcTaskParams::ProcTaskParams(const ProcTaskParams& other) = - default; - -HostResolverImpl::ProcTaskParams::~ProcTaskParams() = default; - HostResolverImpl::HostResolverImpl(const Options& options, NetLog* net_log) : max_queued_jobs_(0), proc_params_(NULL, options.max_retry_attempts), @@ -2660,7 +2639,7 @@ // to lack of detected IPv6 support. (See SystemHostResolverCall for // rationale). if (key.dns_query_type == DnsQueryType::UNSPECIFIED || - DnsQueryTypeToAddressFamily(key.dns_query_type) == + HostResolver::DnsQueryTypeToAddressFamily(key.dns_query_type) == address.GetFamily() || (address.GetFamily() == ADDRESS_FAMILY_IPV6 && key.dns_query_type == DnsQueryType::A && @@ -2909,8 +2888,7 @@ proc_params_.unresponsive_delay = GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault( "DnsUnresponsiveDelayMsByConnectionType", - base::TimeDelta::FromMilliseconds(kDnsDefaultUnresponsiveDelayMs), - type); + ProcTaskParams::kDnsDefaultUnresponsiveDelay, type); } void HostResolverImpl::OnInitialDNSConfigRead() {
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h index 893aeceb..24380e6 100644 --- a/net/dns/host_resolver_impl.h +++ b/net/dns/host_resolver_impl.h
@@ -43,6 +43,12 @@ class NetLog; class NetLogWithSource; +// Scheduler and controller of host resolution requests. Because of the global +// nature of host resolutions, this class is generally expected to be singleton +// within the browser and only be interacted with through per-context +// ContextHostResolver objects (which are themselves generally interacted with +// though the HostResolver interface). +// // For each hostname that is requested, HostResolver creates a // HostResolverImpl::Job. When this job gets dispatched it creates a task // (ProcTask for the system resolver or DnsTask for the async resolver) which @@ -72,48 +78,14 @@ // // Jobs are ordered in the queue based on their priority and order of arrival. class NET_EXPORT HostResolverImpl - : public HostResolver, - public NetworkChangeNotifier::IPAddressObserver, + : public NetworkChangeNotifier::IPAddressObserver, public NetworkChangeNotifier::ConnectionTypeObserver, public NetworkChangeNotifier::DNSObserver { public: - // Parameters for ProcTask which resolves hostnames using HostResolveProc. - // - // |resolver_proc| is used to perform the actual resolves; it must be - // thread-safe since it may be run from multiple worker threads. If - // |resolver_proc| is NULL then the default host resolver procedure is - // used (which is SystemHostResolverProc except if overridden). - // - // For each attempt, we could start another attempt if host is not resolved - // within |unresponsive_delay| time. We keep attempting to resolve the host - // for |max_retry_attempts|. For every retry attempt, we grow the - // |unresponsive_delay| by the |retry_factor| amount (that is retry interval - // is multiplied by the retry factor each time). Once we have retried - // |max_retry_attempts|, we give up on additional attempts. - // - struct NET_EXPORT_PRIVATE ProcTaskParams { - // Sets up defaults. - ProcTaskParams(HostResolverProc* resolver_proc, size_t max_retry_attempts); - - ProcTaskParams(const ProcTaskParams& other); - - ~ProcTaskParams(); - - // The procedure to use for resolving host names. This will be NULL, except - // in the case of unit-tests which inject custom host resolving behaviors. - scoped_refptr<HostResolverProc> resolver_proc; - - // Maximum number retry attempts to resolve the hostname. - // Pass HostResolver::kDefaultRetryAttempts to choose a default value. - size_t max_retry_attempts; - - // This is the limit after which we make another attempt to resolve the host - // if the worker thread has not responded yet. - base::TimeDelta unresponsive_delay; - - // Factor to grow |unresponsive_delay| when we re-re-try. - uint32_t retry_factor; - }; + using MdnsListener = HostResolver::MdnsListener; + using Options = HostResolver::Options; + using ResolveHostRequest = HostResolver::ResolveHostRequest; + using ResolveHostParameters = HostResolver::ResolveHostParameters; // Creates a HostResolver as specified by |options|. Blocking tasks are run in // TaskScheduler. @@ -143,20 +115,18 @@ std::unique_ptr<ResolveHostRequest> CreateRequest( const HostPortPair& host, const NetLogWithSource& net_log, - const base::Optional<ResolveHostParameters>& optional_parameters) - override; - std::unique_ptr<MdnsListener> CreateMdnsListener( - const HostPortPair& host, - DnsQueryType query_type) override; - void SetDnsClientEnabled(bool enabled) override; + const base::Optional<ResolveHostParameters>& optional_parameters); + std::unique_ptr<MdnsListener> CreateMdnsListener(const HostPortPair& host, + DnsQueryType query_type); + void SetDnsClientEnabled(bool enabled); - HostCache* GetHostCache() override; + HostCache* GetHostCache(); bool HasCached(base::StringPiece hostname, HostCache::Entry::Source* source_out, HostCache::EntryStaleness* stale_out, - bool* secure_out) const override; + bool* secure_out) const; - std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; + std::unique_ptr<base::Value> GetDnsConfigAsValue() const; // Returns the number of host cache entries that were restored, or 0 if there // is no cache. @@ -164,14 +134,14 @@ // Returns the number of entries in the host cache, or 0 if there is no cache. size_t CacheSize() const; - void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override; - bool GetNoIPv6OnWifi() override; + void SetNoIPv6OnWifi(bool no_ipv6_on_wifi); + bool GetNoIPv6OnWifi(); - void SetDnsConfigOverrides(const DnsConfigOverrides& overrides) override; + void SetDnsConfigOverrides(const DnsConfigOverrides& overrides); - void SetRequestContext(URLRequestContext* request_context) override; + void SetRequestContext(URLRequestContext* request_context); const std::vector<DnsConfig::DnsOverHttpsServerConfig>* - GetDnsOverHttpsServersForTesting() const override; + GetDnsOverHttpsServersForTesting() const; void set_proc_params_for_test(const ProcTaskParams& proc_params) { proc_params_ = proc_params;
diff --git a/net/dns/host_resolver_impl_fuzzer.cc b/net/dns/host_resolver_impl_fuzzer.cc index a16bebc4..20f33e4a 100644 --- a/net/dns/host_resolver_impl_fuzzer.cc +++ b/net/dns/host_resolver_impl_fuzzer.cc
@@ -17,10 +17,11 @@ #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" -#include "net/dns/fuzzed_host_resolver.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/dns/host_resolver.h" #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" +#include "net/net_buildflags.h" namespace { @@ -206,7 +207,8 @@ options.max_concurrent_resolves = data_provider.ConsumeIntegralInRange(1, 8); options.enable_caching = data_provider.ConsumeBool(); - net::FuzzedHostResolver host_resolver(options, &net_log, &data_provider); + net::FuzzedContextHostResolver host_resolver(options, &net_log, + &data_provider); host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool()); std::vector<std::unique_ptr<DnsRequest>> dns_requests;
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc index 1238156..19f8ef7 100644 --- a/net/dns/host_resolver_impl_unittest.cc +++ b/net/dns/host_resolver_impl_unittest.cc
@@ -82,9 +82,8 @@ return options; } -HostResolverImpl::ProcTaskParams DefaultParams( - HostResolverProc* resolver_proc) { - return HostResolverImpl::ProcTaskParams(resolver_proc, kMaxRetryAttempts); +ProcTaskParams DefaultParams(HostResolverProc* resolver_proc) { + return ProcTaskParams(resolver_proc, kMaxRetryAttempts); } // A HostResolverProc that pushes each host mapped into a list and allows @@ -479,7 +478,7 @@ // This HostResolverImpl will only allow 1 outstanding resolve at a time and // perform no retries. void CreateSerialResolver() { - HostResolverImpl::ProcTaskParams params = DefaultParams(proc_.get()); + ProcTaskParams params = DefaultParams(proc_.get()); params.max_retry_attempts = 0u; CreateResolverWithLimitsAndParams(1u, params, true /* ipv6_reachable */); } @@ -494,10 +493,9 @@ EXPECT_FALSE(proc_->HasBlockedRequests()); } - virtual void CreateResolverWithLimitsAndParams( - size_t max_concurrent_resolves, - const HostResolverImpl::ProcTaskParams& params, - bool ipv6_reachable) { + virtual void CreateResolverWithLimitsAndParams(size_t max_concurrent_resolves, + const ProcTaskParams& params, + bool ipv6_reachable) { HostResolverImpl::Options options = DefaultOptions(); options.max_concurrent_resolves = max_concurrent_resolves; resolver_.reset(new TestHostResolverImpl(options, NULL, ipv6_reachable)); @@ -1775,7 +1773,7 @@ new LookupAttemptHostResolverProc(NULL, kAttemptNumberToResolve, kTotalAttempts)); - HostResolverImpl::ProcTaskParams params = DefaultParams(resolver_proc.get()); + ProcTaskParams params = DefaultParams(resolver_proc.get()); base::TimeDelta unresponsive_delay = params.unresponsive_delay; int retry_factor = params.retry_factor; @@ -2816,10 +2814,9 @@ } // HostResolverImplTest implementation: - void CreateResolverWithLimitsAndParams( - size_t max_concurrent_resolves, - const HostResolverImpl::ProcTaskParams& params, - bool ipv6_reachable) override { + void CreateResolverWithLimitsAndParams(size_t max_concurrent_resolves, + const ProcTaskParams& params, + bool ipv6_reachable) override { HostResolverImpl::Options options = DefaultOptions(); options.max_concurrent_resolves = max_concurrent_resolves; resolver_.reset(new TestHostResolverImpl(options, NULL, ipv6_reachable));
diff --git a/net/dns/host_resolver_proc.cc b/net/dns/host_resolver_proc.cc index 94fcaaa..ab5e16f 100644 --- a/net/dns/host_resolver_proc.cc +++ b/net/dns/host_resolver_proc.cc
@@ -14,6 +14,7 @@ #include "net/base/sys_addrinfo.h" #include "net/dns/dns_reloader.h" #include "net/dns/dns_util.h" +#include "net/dns/host_resolver.h" #if defined(OS_OPENBSD) #define AI_ADDRCONFIG 0 @@ -275,4 +276,23 @@ SystemHostResolverProc::~SystemHostResolverProc() = default; +const base::TimeDelta ProcTaskParams::kDnsDefaultUnresponsiveDelay = + base::TimeDelta::FromSeconds(6); + +ProcTaskParams::ProcTaskParams(HostResolverProc* resolver_proc, + size_t max_retry_attempts) + : resolver_proc(resolver_proc), + max_retry_attempts(max_retry_attempts), + unresponsive_delay(kDnsDefaultUnresponsiveDelay), + retry_factor(2) { + // Maximum of 4 retry attempts for host resolution. + static const size_t kDefaultMaxRetryAttempts = 4u; + if (max_retry_attempts == HostResolver::kDefaultRetryAttempts) + max_retry_attempts = kDefaultMaxRetryAttempts; +} + +ProcTaskParams::ProcTaskParams(const ProcTaskParams& other) = default; + +ProcTaskParams::~ProcTaskParams() = default; + } // namespace net
diff --git a/net/dns/host_resolver_proc.h b/net/dns/host_resolver_proc.h index 182298b7f..36bdb1f 100644 --- a/net/dns/host_resolver_proc.h +++ b/net/dns/host_resolver_proc.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/time/time.h" #include "net/base/address_family.h" #include "net/base/net_export.h" @@ -108,6 +109,48 @@ DISALLOW_COPY_AND_ASSIGN(SystemHostResolverProc); }; +// Parameters for customizing HostResolverProc behavior in HostResolvers. +// +// |resolver_proc| is used to perform the actual resolves; it must be +// thread-safe since it may be run from multiple worker threads. If +// |resolver_proc| is NULL then the default host resolver procedure is +// used (which is SystemHostResolverProc except if overridden). +// +// For each attempt, we could start another attempt if host is not resolved +// within |unresponsive_delay| time. We keep attempting to resolve the host +// for |max_retry_attempts|. For every retry attempt, we grow the +// |unresponsive_delay| by the |retry_factor| amount (that is retry interval +// is multiplied by the retry factor each time). Once we have retried +// |max_retry_attempts|, we give up on additional attempts. +// +struct NET_EXPORT_PRIVATE ProcTaskParams { + // Default delay between calls to the system resolver for the same hostname. + // (Can be overridden by field trial.) + static const base::TimeDelta kDnsDefaultUnresponsiveDelay; + + // Sets up defaults. + ProcTaskParams(HostResolverProc* resolver_proc, size_t max_retry_attempts); + + ProcTaskParams(const ProcTaskParams& other); + + ~ProcTaskParams(); + + // The procedure to use for resolving host names. This will be NULL, except + // in the case of unit-tests which inject custom host resolving behaviors. + scoped_refptr<HostResolverProc> resolver_proc; + + // Maximum number retry attempts to resolve the hostname. + // Pass HostResolver::kDefaultRetryAttempts to choose a default value. + size_t max_retry_attempts; + + // This is the limit after which we make another attempt to resolve the host + // if the worker thread has not responded yet. + base::TimeDelta unresponsive_delay; + + // Factor to grow |unresponsive_delay| when we re-re-try. + uint32_t retry_factor; +}; + } // namespace net #endif // NET_DNS_HOST_RESOLVER_PROC_H_
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc index 2829cb4a..46139820 100644 --- a/net/http/http_proxy_client_socket_wrapper.cc +++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -40,9 +40,10 @@ HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper( const OnProxyAuthChallengeCallback& on_proxy_auth_callback, RequestPriority priority, + const SocketTag& socket_tag, base::TimeDelta connect_timeout_duration, base::TimeDelta proxy_negotiation_timeout_duration, - const CommonConnectJobParams& common_connect_job_params, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& transport_params, const scoped_refptr<SSLSocketParams>& ssl_params, quic::QuicTransportVersion quic_version, @@ -59,6 +60,7 @@ : on_proxy_auth_callback_(on_proxy_auth_callback), next_state_(STATE_NONE), priority_(priority), + socket_tag_(socket_tag), connect_timeout_duration_(connect_timeout_duration), proxy_negotiation_timeout_duration_(proxy_negotiation_timeout_duration), transport_params_(transport_params), @@ -81,7 +83,7 @@ GetDestination().ToString()), http_auth_cache, http_auth_handler_factory, - common_connect_job_params_.host_resolver) + common_connect_job_params_->host_resolver) : nullptr), net_log_(NetLogWithSource::Make( net_log.net_log(), @@ -527,8 +529,8 @@ int HttpProxyClientSocketWrapper::DoTransportConnect() { next_state_ = STATE_TCP_CONNECT_COMPLETE; nested_connect_job_ = TransportConnectJob::CreateTransportConnectJob( - transport_params_, priority_, common_connect_job_params_, this, - &net_log_); + transport_params_, priority_, socket_tag_, common_connect_job_params_, + this, &net_log_); return nested_connect_job_->Connect(); } @@ -561,8 +563,7 @@ if (tunnel_) { SpdySessionKey key(ssl_params_->GetDirectConnectionParams()->destination(), ProxyServer::Direct(), PRIVACY_MODE_DISABLED, - SpdySessionKey::IsProxySession::kTrue, - common_connect_job_params_.socket_tag); + SpdySessionKey::IsProxySession::kTrue, socket_tag_); if (spdy_session_pool_->FindAvailableSession( key, /* enable_ip_based_pooling = */ true, /* is_websocket = */ false, net_log_)) { @@ -573,7 +574,8 @@ } next_state_ = STATE_SSL_CONNECT_COMPLETE; nested_connect_job_ = std::make_unique<SSLConnectJob>( - priority_, common_connect_job_params_, ssl_params_, this, &net_log_); + priority_, socket_tag_, common_connect_job_params_, ssl_params_, this, + &net_log_); return nested_connect_job_->Connect(); } @@ -650,12 +652,13 @@ // Add a HttpProxy connection on top of the tcp socket. transport_socket_ = - common_connect_job_params_.client_socket_factory->CreateProxyClientSocket( - nested_connect_job_->PassSocket(), user_agent_, endpoint_, - ProxyServer(GetProxyServerScheme(), GetDestination()), - http_auth_controller_.get(), tunnel_, using_spdy_, - negotiated_protocol_, common_connect_job_params_.proxy_delegate, - ssl_params_.get() != nullptr, traffic_annotation_); + common_connect_job_params_->client_socket_factory + ->CreateProxyClientSocket( + nested_connect_job_->PassSocket(), user_agent_, endpoint_, + ProxyServer(GetProxyServerScheme(), GetDestination()), + http_auth_controller_.get(), tunnel_, using_spdy_, + negotiated_protocol_, common_connect_job_params_->proxy_delegate, + ssl_params_.get() != nullptr, traffic_annotation_); nested_connect_job_.reset(); return transport_socket_->Connect(base::Bind( &HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this))); @@ -683,8 +686,7 @@ DCHECK(ssl_params_); SpdySessionKey key(ssl_params_->GetDirectConnectionParams()->destination(), ProxyServer::Direct(), PRIVACY_MODE_DISABLED, - SpdySessionKey::IsProxySession::kTrue, - common_connect_job_params_.socket_tag); + SpdySessionKey::IsProxySession::kTrue, socket_tag_); base::WeakPtr<SpdySession> spdy_session = spdy_session_pool_->FindAvailableSession( key, /* enable_ip_based_pooling = */ true, @@ -705,8 +707,8 @@ spdy_stream_request_ = std::make_unique<SpdyStreamRequest>(); return spdy_stream_request_->StartRequest( SPDY_BIDIRECTIONAL_STREAM, spdy_session, - GURL("https://" + endpoint_.ToString()), priority_, - common_connect_job_params_.socket_tag, spdy_session->net_log(), + GURL("https://" + endpoint_.ToString()), priority_, socket_tag_, + spdy_session->net_log(), base::Bind(&HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this)), traffic_annotation_); @@ -739,8 +741,7 @@ std::make_unique<QuicStreamRequest>(quic_stream_factory_); return quic_stream_request_->Request( proxy_server, quic_version_, ssl_params_->privacy_mode(), priority_, - common_connect_job_params_.socket_tag, - ssl_params_->ssl_config().GetCertVerifyFlags(), + socket_tag_, ssl_params_->ssl_config().GetCertVerifyFlags(), GURL("https://" + proxy_server.ToString()), net_log_, &quic_net_error_details_, /*failed_on_default_network_callback=*/CompletionOnceCallback(),
diff --git a/net/http/http_proxy_client_socket_wrapper.h b/net/http/http_proxy_client_socket_wrapper.h index 2284743e..2882f00 100644 --- a/net/http/http_proxy_client_socket_wrapper.h +++ b/net/http/http_proxy_client_socket_wrapper.h
@@ -27,6 +27,7 @@ #include "net/quic/quic_stream_factory.h" #include "net/socket/connect_job.h" #include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" #include "net/socket/ssl_client_socket.h" #include "net/spdy/spdy_session.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -64,9 +65,10 @@ HttpProxyClientSocketWrapper( const OnProxyAuthChallengeCallback& on_proxy_auth_callback, RequestPriority priority, + const SocketTag& socket_tag, base::TimeDelta connect_timeout_duration, base::TimeDelta proxy_negotiation_timeout_duration, - const CommonConnectJobParams& common_connect_job_params, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& transport_params, const scoped_refptr<SSLSocketParams>& ssl_params, quic::QuicTransportVersion quic_version, @@ -205,6 +207,7 @@ State next_state_; RequestPriority priority_; + const SocketTag socket_tag_; const base::TimeDelta connect_timeout_duration_; const base::TimeDelta proxy_negotiation_timeout_duration_; @@ -220,7 +223,7 @@ bool has_restarted_; const bool tunnel_; - const CommonConnectJobParams common_connect_job_params_; + const CommonConnectJobParams* common_connect_job_params_; bool using_spdy_; bool is_trusted_proxy_;
diff --git a/net/http/http_proxy_connect_job.cc b/net/http/http_proxy_connect_job.cc index de7c208..6e1ed3d4 100644 --- a/net/http/http_proxy_connect_job.cc +++ b/net/http/http_proxy_connect_job.cc
@@ -166,11 +166,13 @@ HttpProxyConnectJob::HttpProxyConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<HttpProxySocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log) : ConnectJob(priority, + socket_tag, base::TimeDelta() /* The socket takes care of timeouts */, common_connect_job_params, delegate, @@ -181,9 +183,10 @@ base::BindRepeating(&HttpProxyConnectJob::OnNeedsProxyAuth, base::Unretained(this)), priority, + socket_tag, ConnectionTimeout( *params, - common_connect_job_params.network_quality_estimator), + common_connect_job_params->network_quality_estimator), kHttpProxyConnectJobTunnelTimeout, common_connect_job_params, params->transport_params(),
diff --git a/net/http/http_proxy_connect_job.h b/net/http/http_proxy_connect_job.h index ba3eece..6082729 100644 --- a/net/http/http_proxy_connect_job.h +++ b/net/http/http_proxy_connect_job.h
@@ -27,6 +27,7 @@ class HttpAuthHandlerFactory; class HttpProxyClientSocketWrapper; class NetworkQualityEstimator; +class SocketTag; class SpdySessionPool; class SSLSocketParams; class TransportSocketParams; @@ -102,7 +103,8 @@ class NET_EXPORT_PRIVATE HttpProxyConnectJob : public ConnectJob { public: HttpProxyConnectJob(RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<HttpProxySocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log);
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc index e69a00b..4000f8a 100644 --- a/net/http/http_proxy_connect_job_unittest.cc +++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -70,6 +70,7 @@ network_quality_estimator_ = std::make_unique<TestNetworkQualityEstimator>(); session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); + InitCommonConnectJobParams(); } virtual ~HttpProxyConnectJobTest() { @@ -158,32 +159,38 @@ ConnectJob::Delegate* delegate, RequestPriority priority) { return std::make_unique<HttpProxyConnectJob>( - priority, - CommonConnectJobParams( - "group_name", SocketTag(), &socket_factory_, - session_deps_.host_resolver.get(), proxy_delegate_.get(), - SSLClientSocketContext( - session_deps_.cert_verifier.get(), - session_deps_.channel_id_service.get(), - session_deps_.transport_security_state.get(), - session_deps_.cert_transparency_verifier.get(), - session_deps_.ct_policy_enforcer.get(), - nullptr /* ssl_session_cache_arg */), - SSLClientSocketContext( - session_deps_.cert_verifier.get(), - session_deps_.channel_id_service.get(), - session_deps_.transport_security_state.get(), - session_deps_.cert_transparency_verifier.get(), - session_deps_.ct_policy_enforcer.get(), - nullptr /* ssl_session_cache_arg */), - nullptr /* socket_performance_watcher_factory */, - network_quality_estimator_.get(), nullptr /* net_log */, - nullptr /* websocket_endpoint_lock_manager */), + priority, SocketTag(), common_connect_job_params_.get(), std::move(http_proxy_socket_params), delegate, nullptr /* net_log */); } + // This may only be called at the start of the test, before any ConnectJobs + // have been created. void InitProxyDelegate() { proxy_delegate_ = std::make_unique<TestProxyDelegate>(); + InitCommonConnectJobParams(); + } + + // This may only be called at the start of the test, before any ConnectJobs + // have been created. + void InitCommonConnectJobParams() { + common_connect_job_params_ = std::make_unique<CommonConnectJobParams>( + &socket_factory_, session_deps_.host_resolver.get(), + proxy_delegate_.get(), + SSLClientSocketContext(session_deps_.cert_verifier.get(), + session_deps_.channel_id_service.get(), + session_deps_.transport_security_state.get(), + session_deps_.cert_transparency_verifier.get(), + session_deps_.ct_policy_enforcer.get(), + nullptr /* ssl_session_cache_arg */), + SSLClientSocketContext(session_deps_.cert_verifier.get(), + session_deps_.channel_id_service.get(), + session_deps_.transport_security_state.get(), + session_deps_.cert_transparency_verifier.get(), + session_deps_.ct_policy_enforcer.get(), + nullptr /* ssl_session_cache_arg */), + nullptr /* socket_performance_watcher_factory */, + network_quality_estimator_.get(), nullptr /* net_log */, + nullptr /* websocket_endpoint_lock_manager */); } void Initialize(base::span<const MockRead> reads, @@ -242,6 +249,8 @@ SpdyTestUtil spdy_util_; TestCompletionCallback callback_; + + std::unique_ptr<CommonConnectJobParams> common_connect_job_params_; }; // All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h index c2531a3f..0688dd0 100644 --- a/net/log/net_log_event_type_list.h +++ b/net/log/net_log_event_type_list.h
@@ -7,6 +7,7 @@ // The following line silences a presubmit warning that would otherwise be // triggered by this: // no-include-guard-because-multiply-included +// NOLINT(build/header_guard) // In the event of a failure, a many end events will have a |net_error| // parameter with the integer error code associated with the failure. Most @@ -785,8 +786,13 @@ // } EVENT_TYPE(TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS) -// A backup connect job is created due to slow connect. -EVENT_TYPE(BACKUP_CONNECT_JOB_CREATED) +// A connect job is created by a socket pool. Its parameters are: +// { +// "backup_job": <Whether this is a backup job created because the other +// ConnectJob was taking too long>, +// "group_name": <The group name for the socket request>, +// } +EVENT_TYPE(SOCKET_POOL_CONNECT_JOB_CREATED) // This event is sent when a connect job is eventually bound to a request // (because of late binding and socket backup jobs, we don't assign the job to
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc index 78bc90a8..4607d9f 100644 --- a/net/network_error_logging/network_error_logging_service.cc +++ b/net/network_error_logging/network_error_logging_service.cc
@@ -207,17 +207,20 @@ OriginPolicy policy; policy.origin = origin; policy.received_ip_address = received_ip_address; + policy.last_used = clock_->Now(); HeaderOutcome outcome = ParseHeader(value, clock_->Now(), &policy); RecordHeaderOutcome(outcome); if (outcome != HeaderOutcome::SET && outcome != HeaderOutcome::REMOVED) return; + // If a policy for |origin| already existed, remove the old poliicy. auto it = policies_.find(origin); - if (it != policies_.end()) { - MaybeRemoveWildcardPolicy(origin, &it->second); - policies_.erase(it); - } + if (it != policies_.end()) + RemovePolicy(it); + // A policy's |expires| field is set to a null time if the max_age was 0. + // Having a max_age of 0 means that the policy should be removed, so return + // here instead of continuing on to inserting the policy. if (policy.expires.is_null()) return; @@ -225,6 +228,14 @@ auto inserted = policies_.insert(std::make_pair(origin, policy)); DCHECK(inserted.second); MaybeAddWildcardPolicy(origin, &inserted.first->second); + + // Evict policies if the policy limit is exceeded. + if (policies_.size() > kMaxPolicies) { + RemoveAllExpiredPolicies(); + while (policies_.size() > kMaxPolicies) { + EvictStalestPolicy(); + } + } } void OnRequest(RequestDetails details) override { @@ -246,6 +257,9 @@ return; } + // Mark the policy used. + policy->last_used = clock_->Now(); + Error type = details.type; // It is expected for Reporting uploads to terminate with ERR_ABORTED, since // the ReportingUploader cancels them after receiving the response code and @@ -338,6 +352,10 @@ RequestOutcome::kDiscardedNoOriginPolicy); return; } + + // Mark the policy used. + policy->last_used = clock_->Now(); + if (IsMismatchingSubdomainReport(*policy, report_origin)) { RecordSignedExchangeRequestOutcome( RequestOutcome::kDiscardedNonDNSSubdomainReport); @@ -371,17 +389,14 @@ void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override { - std::vector<url::Origin> origins_to_remove; - - for (auto it = policies_.begin(); it != policies_.end(); ++it) { - if (origin_filter.Run(it->first.GetURL())) - origins_to_remove.push_back(it->first); - } - - for (auto it = origins_to_remove.begin(); it != origins_to_remove.end(); - ++it) { - MaybeRemoveWildcardPolicy(*it, &policies_[*it]); - policies_.erase(*it); + for (auto it = policies_.begin(); it != policies_.end();) { + const url::Origin& origin = it->first; + // Remove policies matching the filter. + if (origin_filter.Run(origin.GetURL())) { + it = RemovePolicy(it); + } else { + ++it; + } } } @@ -437,6 +452,10 @@ double success_fraction; double failure_fraction; bool include_subdomains; + + // Last time the policy was accessed to create a report, even if no report + // ends up being queued. Also updated when the policy is first set. + mutable base::Time last_used; }; // Map from origin to origin's (owned) policy. @@ -524,7 +543,6 @@ } const OriginPolicy* FindPolicyForOrigin(const url::Origin& origin) const { - // TODO(juliatuttle): Clean out expired policies sometime/somewhere. auto it = policies_.find(origin); if (it != policies_.end() && clock_->Now() < it->second.expires) return &it->second; @@ -576,14 +594,24 @@ DCHECK(inserted.second); } - void MaybeRemoveWildcardPolicy(const url::Origin& origin, - const OriginPolicy* policy) { + // Removes the policy pointed to by |policy_it|. Invalidates |policy_it|. + // Returns the iterator to the next element. + PolicyMap::iterator RemovePolicy(PolicyMap::iterator policy_it) { + DCHECK(policy_it != policies_.end()); + OriginPolicy* policy = &policy_it->second; + MaybeRemoveWildcardPolicy(policy); + return policies_.erase(policy_it); + } + + void MaybeRemoveWildcardPolicy(const OriginPolicy* policy) { DCHECK(policy); - DCHECK_EQ(policy, &policies_[origin]); if (!policy->include_subdomains) return; + const url::Origin& origin = policy->origin; + DCHECK_EQ(policy, &policies_[origin]); + auto wildcard_it = wildcard_policies_.find(origin.host()); DCHECK(wildcard_it != wildcard_policies_.end()); @@ -593,6 +621,30 @@ wildcard_policies_.erase(wildcard_it); } + void RemoveAllExpiredPolicies() { + for (auto it = policies_.begin(); it != policies_.end();) { + if (it->second.expires < clock_->Now()) { + it = RemovePolicy(it); + } else { + ++it; + } + } + } + + void EvictStalestPolicy() { + PolicyMap::iterator stalest_it = policies_.begin(); + for (auto it = policies_.begin(); it != policies_.end(); ++it) { + if (it->second.last_used < stalest_it->second.last_used) + stalest_it = it; + } + + // This should only be called if we have hit the max policy limit, so there + // should be at least one policy. + DCHECK(stalest_it != policies_.end()); + + RemovePolicy(stalest_it); + } + std::unique_ptr<const base::Value> CreateReportBody( const std::string& phase, const std::string& type, @@ -715,6 +767,9 @@ const char NetworkErrorLoggingService::kInnerUrlKey[] = "inner_url"; const char NetworkErrorLoggingService::kCertUrlKey[] = "cert_url"; +// See also: max number of Reporting endpoints specified in ReportingPolicy. +const size_t NetworkErrorLoggingService::kMaxPolicies = 1000u; + // static void NetworkErrorLoggingService:: RecordHeaderDiscardedForNoNetworkErrorLoggingService() {
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h index 812d8b9..7527ff1b 100644 --- a/net/network_error_logging/network_error_logging_service.h +++ b/net/network_error_logging/network_error_logging_service.h
@@ -115,6 +115,9 @@ static const char kInnerUrlKey[]; static const char kCertUrlKey[]; + // Maximum number of NEL policies to store before evicting. + static const size_t kMaxPolicies; + // Histograms. These are mainly used in test cases to verify that interesting // events occurred.
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc index 8ff36e0..89eae7da 100644 --- a/net/network_error_logging/network_error_logging_service_unittest.cc +++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" +#include "base/strings/stringprintf.h" #include "base/test/simple_test_clock.h" #include "base/test/values_test_util.h" #include "base/time/time.h" @@ -185,6 +186,21 @@ return reporting_service_->reports(); } + const url::Origin MakeOrigin(size_t index) { + GURL url(base::StringPrintf("https://example%zd.com/", index)); + return url::Origin::Create(url); + } + + // Returns whether the NetworkErrorLoggingService has a policy corresponding + // to |origin|. Returns true if so, even if the policy is expired. + bool HasPolicyForOrigin(const url::Origin& origin) { + std::set<url::Origin> all_policy_origins = + service_->GetPolicyOriginsForTesting(); + return all_policy_origins.find(origin) != all_policy_origins.end(); + } + + size_t PolicyCount() { return service_->GetPolicyOriginsForTesting().size(); } + const GURL kUrl_ = GURL("https://example.com/path"); const GURL kUrlDifferentPort_ = GURL("https://example.com:4433/path"); const GURL kUrlSubdomain_ = GURL("https://subdomain.example.com/path"); @@ -585,8 +601,11 @@ TEST_F(NetworkErrorLoggingServiceTest, MaxAge0) { service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + EXPECT_EQ(1u, PolicyCount()); + // Max_age of 0 removes the policy. service()->OnHeader(kOrigin_, kServerIP_, kHeaderMaxAge0_); + EXPECT_EQ(0u, PolicyCount()); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -775,22 +794,31 @@ TEST_F(NetworkErrorLoggingServiceTest, RemoveAllBrowsingData) { service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + EXPECT_EQ(1u, PolicyCount()); + EXPECT_TRUE(HasPolicyForOrigin(kOrigin_)); service()->RemoveAllBrowsingData(); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); + EXPECT_EQ(0u, PolicyCount()); + EXPECT_FALSE(HasPolicyForOrigin(kOrigin_)); EXPECT_TRUE(reports().empty()); } TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) { service()->OnHeader(kOrigin_, kServerIP_, kHeader_); service()->OnHeader(kOriginDifferentHost_, kServerIP_, kHeader_); + EXPECT_EQ(2u, PolicyCount()); + // Remove policy for kOrigin_ but not kOriginDifferentHost_ service()->RemoveBrowsingData( base::BindRepeating([](const GURL& origin) -> bool { return origin.host() == "example.com"; })); + EXPECT_EQ(1u, PolicyCount()); + EXPECT_TRUE(HasPolicyForOrigin(kOriginDifferentHost_)); + EXPECT_FALSE(HasPolicyForOrigin(kOrigin_)); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -1034,5 +1062,86 @@ EXPECT_TRUE(reports().empty()); } +// When the max number of policies is exceeded, first try to remove expired +// policies before evicting the least recently used unexpired policy. +TEST_F(NetworkErrorLoggingServiceTest, EvictAllExpiredPoliciesFirst) { + base::SimpleTestClock clock; + service()->SetClockForTesting(&clock); + + // Add 100 policies then make them expired. + for (size_t i = 0; i < 100; ++i) { + service()->OnHeader(MakeOrigin(i), kServerIP_, kHeader_); + } + EXPECT_EQ(100u, PolicyCount()); + clock.Advance(base::TimeDelta::FromSeconds(86401)); // max_age is 86400 sec + // Expired policies are allowed to linger before hitting the policy limit. + EXPECT_EQ(100u, PolicyCount()); + + // Reach the max policy limit. + for (size_t i = 100; i < NetworkErrorLoggingService::kMaxPolicies; ++i) { + service()->OnHeader(MakeOrigin(i), kServerIP_, kHeader_); + } + EXPECT_EQ(NetworkErrorLoggingService::kMaxPolicies, PolicyCount()); + + // Add one more policy to trigger eviction of only the expired policies. + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + EXPECT_EQ(NetworkErrorLoggingService::kMaxPolicies - 100 + 1, PolicyCount()); +} + +TEST_F(NetworkErrorLoggingServiceTest, EvictLeastRecentlyUsedPolicy) { + base::SimpleTestClock clock; + service()->SetClockForTesting(&clock); + + // A policy's |last_used| is updated when it is added + for (size_t i = 0; i < NetworkErrorLoggingService::kMaxPolicies; ++i) { + service()->OnHeader(MakeOrigin(i), kServerIP_, kHeader_); + clock.Advance(base::TimeDelta::FromSeconds(1)); + } + + EXPECT_EQ(PolicyCount(), NetworkErrorLoggingService::kMaxPolicies); + + // Set another policy which triggers eviction. None of the policies have + // expired, so the least recently used (i.e. least recently added) policy + // should be evicted. + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + clock.Advance(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(PolicyCount(), NetworkErrorLoggingService::kMaxPolicies); + + EXPECT_FALSE(HasPolicyForOrigin(MakeOrigin(0))); // evicted + std::set<url::Origin> all_policy_origins = + service()->GetPolicyOriginsForTesting(); + for (size_t i = 1; i < NetworkErrorLoggingService::kMaxPolicies; ++i) { + // Avoid n calls to HasPolicyForOrigin(), which would be O(n^2). + EXPECT_EQ(1u, all_policy_origins.count(MakeOrigin(i))); + } + EXPECT_TRUE(HasPolicyForOrigin(kOrigin_)); + + // Now use the policies in reverse order starting with kOrigin_, then add + // another policy to trigger eviction, to check that the stalest policy is + // identified correctly. + service()->OnRequest( + MakeRequestDetails(kOrigin_.GetURL(), ERR_CONNECTION_REFUSED)); + clock.Advance(base::TimeDelta::FromSeconds(1)); + for (size_t i = NetworkErrorLoggingService::kMaxPolicies - 1; i >= 1; --i) { + service()->OnRequest( + MakeRequestDetails(MakeOrigin(i).GetURL(), ERR_CONNECTION_REFUSED)); + clock.Advance(base::TimeDelta::FromSeconds(1)); + } + service()->OnHeader(kOriginSubdomain_, kServerIP_, kHeader_); + EXPECT_EQ(PolicyCount(), NetworkErrorLoggingService::kMaxPolicies); + + EXPECT_FALSE(HasPolicyForOrigin(kOrigin_)); // evicted + all_policy_origins = service()->GetPolicyOriginsForTesting(); + for (size_t i = NetworkErrorLoggingService::kMaxPolicies - 1; i >= 1; --i) { + // Avoid n calls to HasPolicyForOrigin(), which would be O(n^2). + EXPECT_EQ(1u, all_policy_origins.count(MakeOrigin(i))); + } + EXPECT_TRUE(HasPolicyForOrigin(kOriginSubdomain_)); // most recently added + + // Note: This test advances the clock by ~2000 seconds, which is below the + // specified max_age of 86400 seconds, so none of the policies expire during + // this test. +} + } // namespace } // namespace net
diff --git a/net/nqe/network_quality_estimator_util_unittest.cc b/net/nqe/network_quality_estimator_util_unittest.cc index c907e910..83aeb01 100644 --- a/net/nqe/network_quality_estimator_util_unittest.cc +++ b/net/nqe/network_quality_estimator_util_unittest.cc
@@ -11,8 +11,8 @@ #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/host_resolver.h" -#include "net/dns/host_resolver_impl.h" #include "net/dns/mock_host_resolver.h" #include "net/log/test_net_log.h" #include "testing/gtest/include/gtest/gtest.h" @@ -119,20 +119,20 @@ std::make_unique<BoundTestNetLog>(); BoundTestNetLog* net_log_ptr = net_log.get(); - net::HostResolver::Options options; - // Use HostResolverImpl since MockCachingHostResolver does not determine the - // correct answer for localhosts. - HostResolverImpl resolver(options, net_log_ptr->bound().net_log()); + // Use actual HostResolver since MockCachingHostResolver does not determine + // the correct answer for localhosts. + std::unique_ptr<ContextHostResolver> resolver = + HostResolver::CreateDefaultResolverImpl(net_log_ptr->bound().net_log()); scoped_refptr<net::RuleBasedHostResolverProc> rules( new net::RuleBasedHostResolverProc(nullptr)); - EXPECT_TRUE(IsPrivateHost(&resolver, HostPortPair("localhost", 443))); - EXPECT_TRUE(IsPrivateHost(&resolver, HostPortPair("localhost6", 443))); - EXPECT_TRUE(IsPrivateHost(&resolver, HostPortPair("127.0.0.1", 80))); - EXPECT_TRUE(IsPrivateHost(&resolver, HostPortPair("0.0.0.0", 80))); - EXPECT_TRUE(IsPrivateHost(&resolver, HostPortPair("::1", 80))); - EXPECT_FALSE(IsPrivateHost(&resolver, HostPortPair("google.com", 80))); + EXPECT_TRUE(IsPrivateHost(resolver.get(), HostPortPair("localhost", 443))); + EXPECT_TRUE(IsPrivateHost(resolver.get(), HostPortPair("localhost6", 443))); + EXPECT_TRUE(IsPrivateHost(resolver.get(), HostPortPair("127.0.0.1", 80))); + EXPECT_TRUE(IsPrivateHost(resolver.get(), HostPortPair("0.0.0.0", 80))); + EXPECT_TRUE(IsPrivateHost(resolver.get(), HostPortPair("::1", 80))); + EXPECT_FALSE(IsPrivateHost(resolver.get(), HostPortPair("google.com", 80))); } } // namespace
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h index 174a004..ac1a62a 100644 --- a/net/quic/quic_flags_list.h +++ b/net/quic/quic_flags_list.h
@@ -239,13 +239,6 @@ FLAGS_quic_reloadable_flag_quic_log_cert_name_for_empty_sct, true) -// If true, close connection with INVALID_STOP_WAITING if received a -// STOP_WAITING with least_unacked 0. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_close_connection_with_zero_least_unacked_stop_waiting, - true) - // If true, QuicCryptoServerConfig will correctly rotate configs based on // primary time. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_config_rotation, true) @@ -295,3 +288,15 @@ // If true, enforce that QUIC CHLOs fit in one packet. QUIC_FLAG(bool, FLAGS_quic_enforce_single_packet_chlo, true) + +// If both this flag and gfe2_reloadable_flag_quic_deprecate_ack_bundling_mode +// are true, QuicReceivedPacketManager decides when to send ACKs. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_rpm_decides_when_to_send_acks, + false) + +// If true, instead of send encryption none termination packets, send stateless +// reset in reponse to short headers. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_always_reset_short_header_packets, + false)
diff --git a/net/quic/quic_stream_factory_fuzzer.cc b/net/quic/quic_stream_factory_fuzzer.cc index 8835927..05ddcfa 100644 --- a/net/quic/quic_stream_factory_fuzzer.cc +++ b/net/quic/quic_stream_factory_fuzzer.cc
@@ -12,7 +12,7 @@ #include "net/cert/do_nothing_ct_verifier.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" -#include "net/dns/fuzzed_host_resolver.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/http/http_server_properties_impl.h" #include "net/http/transport_security_state.h" #include "net/quic/mock_crypto_client_stream_factory.h" @@ -83,8 +83,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { base::FuzzedDataProvider data_provider(data, size); - FuzzedHostResolver host_resolver(HostResolver::Options(), nullptr, - &data_provider); + FuzzedContextHostResolver host_resolver(HostResolver::Options(), nullptr, + &data_provider); FuzzedSocketFactory socket_factory(&data_provider); // Initialize this on each loop since some options mutate this.
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc index 52ae592b..9d279e9 100644 --- a/net/quic/quic_test_packet_maker.cc +++ b/net/quic/quic_test_packet_maker.cc
@@ -79,7 +79,8 @@ quic::QuicFramer framer(quic::test::SupportedVersions(quic::ParsedQuicVersion( quic::PROTOCOL_QUIC_CRYPTO, version_)), - clock_->Now(), perspective_); + clock_->Now(), perspective_, + quic::kQuicDefaultConnectionIdLength); size_t max_plaintext_size = framer.GetMaxPlaintextSize(quic::kDefaultMaxPacketSize); char buffer[quic::kDefaultMaxPacketSize]; @@ -691,7 +692,8 @@ } quic::QuicFramer framer(quic::test::SupportedVersions(quic::ParsedQuicVersion( quic::PROTOCOL_QUIC_CRYPTO, version_)), - clock_->Now(), perspective_); + clock_->Now(), perspective_, + quic::kQuicDefaultConnectionIdLength); quic::QuicFrames frames; quic::QuicFrame ack_frame(&ack); frames.push_back(ack_frame); @@ -1187,7 +1189,8 @@ quic::QuicStreamFrameDataProducer* data_producer) { quic::QuicFramer framer(quic::test::SupportedVersions(quic::ParsedQuicVersion( quic::PROTOCOL_QUIC_CRYPTO, version_)), - clock_->Now(), perspective_); + clock_->Now(), perspective_, + quic::kQuicDefaultConnectionIdLength); if (data_producer != nullptr) { framer.set_data_producer(data_producer); }
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc index ad5e522..caae809 100644 --- a/net/socket/client_socket_pool_base.cc +++ b/net/socket/client_socket_pool_base.cc
@@ -36,6 +36,16 @@ // after a certain timeout has passed without receiving an ACK. bool g_connect_backup_jobs_enabled = true; +std::unique_ptr<base::Value> NetLogCreateConnectJobCallback( + bool backup_job, + const std::string* group_name, + net::NetLogCaptureMode capture_mode) { + auto dict = std::make_unique<base::DictionaryValue>(); + dict->SetBoolean("backup_job", backup_job); + dict->SetString("group_name", *group_name); + return std::move(dict); +} + } // namespace namespace internal { @@ -322,8 +332,22 @@ // We couldn't find a socket to reuse, and there's space to allocate one, // so allocate and connect a new one. - std::unique_ptr<ConnectJob> connect_job( - connect_job_factory_->NewConnectJob(group_name, request, this)); + group = GetOrCreateGroup(group_name); + connecting_socket_count_++; + std::unique_ptr<ConnectJob> owned_connect_job( + connect_job_factory_->NewConnectJob(request, group)); + owned_connect_job->net_log().AddEvent( + NetLogEventType::SOCKET_POOL_CONNECT_JOB_CREATED, + base::BindRepeating(&NetLogCreateConnectJobCallback, + false /* backup_job */, &group_name)); + ConnectJob* connect_job = owned_connect_job.get(); + bool was_group_empty = group->IsEmpty(); + // Need to add the ConnectJob to the group before connecting, to ensure + // |group| is not empty. Otherwise, if the ConnectJob calls back into the + // socket pool with a new socket request (Like for DNS over HTTPS), the pool + // would then notice the group is empty, and delete it. That would result in a + // UAF when group is referenced later in this function. + group->AddJob(std::move(owned_connect_job), preconnecting); int rv = connect_job->Connect(); if (rv == OK) { @@ -331,22 +355,17 @@ if (!preconnecting) { HandOutSocket(connect_job->PassSocket(), ClientSocketHandle::UNUSED, connect_job->connect_timing(), handle, base::TimeDelta(), - GetOrCreateGroup(group_name), request.net_log()); + group, request.net_log()); } else { - AddIdleSocket(connect_job->PassSocket(), GetOrCreateGroup(group_name)); + AddIdleSocket(connect_job->PassSocket(), group); } + RemoveConnectJob(connect_job, group); } else if (rv == ERR_IO_PENDING) { - // If we don't have any sockets in this group, set a timer for potentially + // If we didn't have any sockets in this group, set a timer for potentially // creating a new one. If the SYN is lost, this backup socket may complete // before the slow socket, improving end user latency. - Group* group = GetOrCreateGroup(group_name); - if (connect_backup_jobs_enabled_ && group->IsEmpty()) { - group->StartBackupJobTimer(group_name, this); - } - - connecting_socket_count_++; - - group->AddJob(std::move(connect_job), preconnecting); + if (connect_backup_jobs_enabled_ && was_group_empty) + group->StartBackupJobTimer(group_name); } else { LogBoundConnectJobToRequest(connect_job->net_log().source(), request); std::unique_ptr<StreamSocket> error_socket; @@ -355,14 +374,14 @@ connect_job->GetAdditionalErrorState(handle); error_socket = connect_job->PassSocket(); } - Group* group = GetOrCreateGroup(group_name); if (error_socket) { HandOutSocket(std::move(error_socket), ClientSocketHandle::UNUSED, connect_job->connect_timing(), handle, base::TimeDelta(), group, request.net_log()); - } else if (group->IsEmpty()) { - RemoveGroup(group_name); } + RemoveConnectJob(connect_job, group); + if (group->IsEmpty()) + RemoveGroup(group_name); } return rv; @@ -703,7 +722,7 @@ auto it = group_map_.find(group_name); if (it != group_map_.end()) return it->second; - Group* group = new Group; + Group* group = new Group(group_name, this); group_map_[group_name] = group; return group; } @@ -834,122 +853,6 @@ return has_stalled_group; } -void ClientSocketPoolBaseHelper::OnConnectJobComplete( - int result, ConnectJob* job) { - DCHECK_NE(ERR_IO_PENDING, result); - const std::string group_name = job->group_name(); - auto group_it = group_map_.find(group_name); - CHECK(group_it != group_map_.end()); - Group* group = group_it->second; - - std::unique_ptr<StreamSocket> socket = job->PassSocket(); - - // Copies of these are needed because |job| may be deleted before they are - // accessed. - NetLogWithSource job_log = job->net_log(); - LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing(); - - // Check if the ConnectJob is already bound to a Request. If so, complete the - // request. - // - // TODO(mmenke) this logic resembles the case where the job is assigned to a - // request below. Look into merging the logic. - int pending_result; - std::unique_ptr<Request> request = - group->FindAndRemoveBoundRequestForConnectJob(job, &pending_result); - if (request) { - --connecting_socket_count_; - bool handed_out_socket = false; - if (pending_result != OK) { - result = pending_result; - } else { - if (socket) { - handed_out_socket = true; - HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, - connect_timing, request->handle(), base::TimeDelta(), - group, request->net_log()); - } - } - request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, - result); - InvokeUserCallbackLater(request->handle(), request->release_callback(), - result, request->socket_tag()); - if (!handed_out_socket) { - OnAvailableSocketSlot(group_name, group); - CheckForStalledSocketGroups(); - } - return; - } - - // RemoveConnectJob(job, _) must be called by all branches below; - // otherwise, |job| will be leaked. - - if (result == OK) { - DCHECK(socket.get()); - request = group->PopNextUnboundRequest(); - RemoveConnectJob(job, group); - if (request) { - LogBoundConnectJobToRequest(job_log.source(), *request); - HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, - connect_timing, request->handle(), base::TimeDelta(), group, - request->net_log()); - request->net_log().EndEvent(NetLogEventType::SOCKET_POOL); - InvokeUserCallbackLater(request->handle(), request->release_callback(), - result, request->socket_tag()); - } else { - AddIdleSocket(std::move(socket), group); - OnAvailableSocketSlot(group_name, group); - CheckForStalledSocketGroups(); - } - } else { - // If we got a socket, it must contain error information so pass that - // up so that the caller can retrieve it. - bool handed_out_socket = false; - std::unique_ptr<Request> request = group->PopNextUnboundRequest(); - if (request) { - LogBoundConnectJobToRequest(job_log.source(), *request); - job->GetAdditionalErrorState(request->handle()); - RemoveConnectJob(job, group); - if (socket.get()) { - handed_out_socket = true; - HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, - connect_timing, request->handle(), base::TimeDelta(), - group, request->net_log()); - } - request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, - result); - InvokeUserCallbackLater(request->handle(), request->release_callback(), - result, request->socket_tag()); - } else { - RemoveConnectJob(job, group); - } - if (!handed_out_socket) { - OnAvailableSocketSlot(group_name, group); - CheckForStalledSocketGroups(); - } - } -} - -void ClientSocketPoolBaseHelper::OnNeedsProxyAuth( - const HttpResponseInfo& response, - HttpAuthController* auth_controller, - base::OnceClosure restart_with_auth_callback, - ConnectJob* job) { - auto group_it = group_map_.find(job->group_name()); - CHECK(group_it != group_map_.end()); - - const Request* request = group_it->second->BindRequestToConnectJob(job); - // If can't bind the ConnectJob to a request, treat this as a ConnectJob - // failure. - if (!request) { - OnConnectJobComplete(ERR_PROXY_AUTH_REQUESTED, job); - return; - } - - request->proxy_auth_callback().Run(response, auth_controller, - std::move(restart_with_auth_callback)); -} - void ClientSocketPoolBaseHelper::OnIPAddressChanged() { FlushWithError(ERR_NETWORK_CHANGED); } @@ -1153,6 +1056,122 @@ return false; } +void ClientSocketPoolBaseHelper::OnConnectJobComplete(Group* group, + int result, + ConnectJob* job) { + DCHECK_NE(ERR_IO_PENDING, result); + DCHECK(group_map_.find(group->group_name()) != group_map_.end()); + DCHECK_EQ(group, group_map_[group->group_name()]); + + std::unique_ptr<StreamSocket> socket = job->PassSocket(); + + // Copies of these are needed because |job| may be deleted before they are + // accessed. + NetLogWithSource job_log = job->net_log(); + LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing(); + + // Check if the ConnectJob is already bound to a Request. If so, complete the + // request. + // + // TODO(mmenke) this logic resembles the case where the job is assigned to a + // request below. Look into merging the logic. + int pending_result; + std::unique_ptr<Request> request = + group->FindAndRemoveBoundRequestForConnectJob(job, &pending_result); + if (request) { + --connecting_socket_count_; + bool handed_out_socket = false; + if (pending_result != OK) { + result = pending_result; + } else { + if (socket) { + handed_out_socket = true; + HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, + connect_timing, request->handle(), base::TimeDelta(), + group, request->net_log()); + } + } + request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, + result); + InvokeUserCallbackLater(request->handle(), request->release_callback(), + result, request->socket_tag()); + if (!handed_out_socket) { + OnAvailableSocketSlot(group->group_name(), group); + CheckForStalledSocketGroups(); + } + return; + } + + // RemoveConnectJob(job, _) must be called by all branches below; + // otherwise, |job| will be leaked. + + if (result == OK) { + DCHECK(socket.get()); + request = group->PopNextUnboundRequest(); + RemoveConnectJob(job, group); + if (request) { + LogBoundConnectJobToRequest(job_log.source(), *request); + HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, + connect_timing, request->handle(), base::TimeDelta(), group, + request->net_log()); + request->net_log().EndEvent(NetLogEventType::SOCKET_POOL); + InvokeUserCallbackLater(request->handle(), request->release_callback(), + result, request->socket_tag()); + } else { + AddIdleSocket(std::move(socket), group); + OnAvailableSocketSlot(group->group_name(), group); + CheckForStalledSocketGroups(); + } + } else { + // If we got a socket, it must contain error information so pass that + // up so that the caller can retrieve it. + bool handed_out_socket = false; + std::unique_ptr<Request> request = group->PopNextUnboundRequest(); + if (request) { + LogBoundConnectJobToRequest(job_log.source(), *request); + job->GetAdditionalErrorState(request->handle()); + RemoveConnectJob(job, group); + if (socket.get()) { + handed_out_socket = true; + HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, + connect_timing, request->handle(), base::TimeDelta(), + group, request->net_log()); + } + request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, + result); + InvokeUserCallbackLater(request->handle(), request->release_callback(), + result, request->socket_tag()); + } else { + RemoveConnectJob(job, group); + } + if (!handed_out_socket) { + OnAvailableSocketSlot(group->group_name(), group); + CheckForStalledSocketGroups(); + } + } +} + +void ClientSocketPoolBaseHelper::OnNeedsProxyAuth( + Group* group, + const HttpResponseInfo& response, + HttpAuthController* auth_controller, + base::OnceClosure restart_with_auth_callback, + ConnectJob* job) { + DCHECK(group_map_.find(group->group_name()) != group_map_.end()); + DCHECK_EQ(group, group_map_[group->group_name()]); + + const Request* request = group->BindRequestToConnectJob(job); + // If can't bind the ConnectJob to a request, treat this as a ConnectJob + // failure. + if (!request) { + OnConnectJobComplete(group, ERR_PROXY_AUTH_REQUESTED, job); + return; + } + + request->proxy_auth_callback().Run(response, auth_controller, + std::move(restart_with_auth_callback)); +} + void ClientSocketPoolBaseHelper::InvokeUserCallbackLater( ClientSocketHandle* handle, CompletionOnceCallback callback, @@ -1192,8 +1211,12 @@ } } -ClientSocketPoolBaseHelper::Group::Group() - : never_assigned_job_count_(0), +ClientSocketPoolBaseHelper::Group::Group( + const std::string& group_name, + ClientSocketPoolBaseHelper* client_socket_pool_base_helper) + : group_name_(group_name), + client_socket_pool_base_helper_(client_socket_pool_base_helper), + never_assigned_job_count_(0), unbound_requests_(NUM_PRIORITIES), active_socket_count_(0) {} @@ -1205,9 +1228,24 @@ DCHECK(bound_requests_.empty()); } +void ClientSocketPoolBaseHelper::Group::OnConnectJobComplete(int result, + ConnectJob* job) { + DCHECK_NE(ERR_IO_PENDING, result); + client_socket_pool_base_helper_->OnConnectJobComplete(this, result, job); +} + +void ClientSocketPoolBaseHelper::Group::OnNeedsProxyAuth( + const HttpResponseInfo& response, + HttpAuthController* auth_controller, + base::OnceClosure restart_with_auth_callback, + ConnectJob* job) { + client_socket_pool_base_helper_->OnNeedsProxyAuth( + this, response, auth_controller, std::move(restart_with_auth_callback), + job); +} + void ClientSocketPoolBaseHelper::Group::StartBackupJobTimer( - const std::string& group_name, - ClientSocketPoolBaseHelper* pool) { + const std::string& group_name) { // Only allow one timer to run at a time. if (BackupJobTimerIsRunning()) return; @@ -1215,9 +1253,9 @@ // Unretained here is okay because |backup_job_timer_| is // automatically cancelled when it's destroyed. backup_job_timer_.Start( - FROM_HERE, pool->ConnectRetryInterval(), + FROM_HERE, client_socket_pool_base_helper_->ConnectRetryInterval(), base::Bind(&Group::OnBackupJobTimerFired, base::Unretained(this), - group_name, pool)); + group_name)); } bool ClientSocketPoolBaseHelper::Group::BackupJobTimerIsRunning() const { @@ -1289,8 +1327,7 @@ } void ClientSocketPoolBaseHelper::Group::OnBackupJobTimerFired( - std::string group_name, - ClientSocketPoolBaseHelper* pool) { + std::string group_name) { // If there are no more jobs pending, there is no work to do. // If we've done our cleanups correctly, this should not happen. if (jobs_.empty()) { @@ -1314,26 +1351,31 @@ // If our old job is waiting on DNS, or if we can't create any sockets // right now due to limits, just reset the timer. - if (pool->ReachedMaxSocketsLimit() || - !HasAvailableSocketSlot(pool->max_sockets_per_group_) || + if (client_socket_pool_base_helper_->ReachedMaxSocketsLimit() || + !HasAvailableSocketSlot( + client_socket_pool_base_helper_->max_sockets_per_group_) || (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) { - StartBackupJobTimer(group_name, pool); + StartBackupJobTimer(group_name); return; } if (unbound_requests_.empty()) return; - std::unique_ptr<ConnectJob> backup_job = - pool->connect_job_factory_->NewConnectJob( - group_name, *unbound_requests_.FirstMax().value(), pool); - backup_job->net_log().AddEvent(NetLogEventType::BACKUP_CONNECT_JOB_CREATED); + std::unique_ptr<ConnectJob> owned_backup_job = + client_socket_pool_base_helper_->connect_job_factory_->NewConnectJob( + *unbound_requests_.FirstMax().value(), this); + owned_backup_job->net_log().AddEvent( + NetLogEventType::SOCKET_POOL_CONNECT_JOB_CREATED, + base::BindRepeating(&NetLogCreateConnectJobCallback, + true /* backup_job */, &group_name_)); + ConnectJob* backup_job = owned_backup_job.get(); + AddJob(std::move(owned_backup_job), false); + client_socket_pool_base_helper_->connecting_socket_count_++; int rv = backup_job->Connect(); - pool->connecting_socket_count_++; - ConnectJob* raw_backup_job = backup_job.get(); - AddJob(std::move(backup_job), false); - if (rv != ERR_IO_PENDING) - pool->OnConnectJobComplete(rv, raw_backup_job); + if (rv != ERR_IO_PENDING) { + client_socket_pool_base_helper_->OnConnectJobComplete(this, rv, backup_job); + } } void ClientSocketPoolBaseHelper::Group::SanityCheck() const {
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h index 86b13e0..774b5a55 100644 --- a/net/socket/client_socket_pool_base.h +++ b/net/socket/client_socket_pool_base.h
@@ -73,8 +73,7 @@ // ClientSocketPoolBaseHelper. This class is not for external use, please use // ClientSocketPoolBase instead. class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper - : public ConnectJob::Delegate, - public NetworkChangeNotifier::IPAddressObserver { + : public NetworkChangeNotifier::IPAddressObserver { public: using Flags = uint32_t; @@ -155,7 +154,6 @@ virtual ~ConnectJobFactory() {} virtual std::unique_ptr<ConnectJob> NewConnectJob( - const std::string& group_name, const Request& request, ConnectJob::Delegate* delegate) const = 0; @@ -292,13 +290,6 @@ void EnableConnectBackupJobs(); - // ConnectJob::Delegate methods: - void OnConnectJobComplete(int result, ConnectJob* job) override; - void OnNeedsProxyAuth(const HttpResponseInfo& response, - HttpAuthController* auth_controller, - base::OnceClosure restart_with_auth_callback, - ConnectJob* job) override; - // NetworkChangeNotifier::IPAddressObserver methods: void OnIPAddressChanged() override; @@ -347,12 +338,20 @@ // SanityCheck() will always be true, except during the invocation of a // method. So all public methods expect the Group to pass SanityCheck() when // invoked. - class NET_EXPORT_PRIVATE Group { + class NET_EXPORT_PRIVATE Group : public ConnectJob::Delegate { public: using JobList = std::list<std::unique_ptr<ConnectJob>>; - Group(); - ~Group(); + Group(const std::string& group_name, + ClientSocketPoolBaseHelper* client_socket_pool_base_helper); + ~Group() override; + + // ConnectJob::Delegate methods: + void OnConnectJobComplete(int result, ConnectJob* job) override; + void OnNeedsProxyAuth(const HttpResponseInfo& response, + HttpAuthController* auth_controller, + base::OnceClosure restart_with_auth_callback, + ConnectJob* job) override; bool IsEmpty() const { return active_socket_count_ == 0 && idle_sockets_.empty() && @@ -389,8 +388,7 @@ // Set a timer to create a backup job if it takes too long to // create one and if a timer isn't already running. - void StartBackupJobTimer(const std::string& group_name, - ClientSocketPoolBaseHelper* pool); + void StartBackupJobTimer(const std::string& group_name); bool BackupJobTimerIsRunning() const; @@ -471,6 +469,7 @@ bool RequestWithHandleHasJobForTesting( const ClientSocketHandle* handle) const; + const std::string& group_name() { return group_name_; } size_t unassigned_job_count() const { return unassigned_jobs_.size(); } const JobList& jobs() const { return jobs_; } const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; } @@ -545,9 +544,7 @@ void TransferJobBetweenRequests(Request* source, Request* dest); // Called when the backup socket timer fires. - void OnBackupJobTimerFired( - std::string group_name, - ClientSocketPoolBaseHelper* pool); + void OnBackupJobTimerFired(std::string group_name); // Checks that: // - |unassigned_jobs_| is empty iff there are at least as many requests @@ -561,6 +558,9 @@ // - There are no duplicate entries in |unassigned_jobs_|. void SanityCheck() const; + const std::string group_name_; + ClientSocketPoolBaseHelper* const client_socket_pool_base_helper_; + // Total number of ConnectJobs that have never been assigned to a Request. // Since jobs use late binding to requests, which ConnectJobs have or have // not been assigned to a request are not tracked. This is incremented on @@ -687,6 +687,15 @@ int rv, const SocketTag& socket_tag); + // These correspond to ConnectJob::Delegate methods, and are invoked by the + // Group a ConnectJob belongs to. + void OnConnectJobComplete(Group* group, int result, ConnectJob* job); + void OnNeedsProxyAuth(Group* group, + const HttpResponseInfo& response, + HttpAuthController* auth_controller, + base::OnceClosure restart_with_auth_callback, + ConnectJob* job); + // Invokes the user callback for |handle|. By the time this task has run, // it's possible that the request has been cancelled, so |handle| may not // exist in |pending_callback_map_|. We look up the callback and result code @@ -780,7 +789,6 @@ virtual ~ConnectJobFactory() {} virtual std::unique_ptr<ConnectJob> NewConnectJob( - const std::string& group_name, const Request& request, ConnectJob::Delegate* delegate) const = 0; @@ -893,10 +901,6 @@ return helper_.DumpMemoryStats(pmd, parent_dump_absolute_name); } - virtual void OnConnectJobComplete(int result, ConnectJob* job) { - return helper_.OnConnectJobComplete(result, job); - } - size_t NumNeverAssignedConnectJobsInGroup( const std::string& group_name) const { return helper_.NumNeverAssignedConnectJobsInGroup(group_name); @@ -955,12 +959,10 @@ ~ConnectJobFactoryAdaptor() override {} std::unique_ptr<ConnectJob> NewConnectJob( - const std::string& group_name, const internal::ClientSocketPoolBaseHelper::Request& request, ConnectJob::Delegate* delegate) const override { const Request& casted_request = static_cast<const Request&>(request); - return connect_job_factory_->NewConnectJob( - group_name, casted_request, delegate); + return connect_job_factory_->NewConnectJob(casted_request, delegate); } const std::unique_ptr<ConnectJobFactory> connect_job_factory_;
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index 07af0295..b753e4c 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -306,26 +306,15 @@ static const int kPendingConnectDelay = 2; TestConnectJob(JobType job_type, - const std::string& group_name, const TestClientSocketPoolBase::Request& request, base::TimeDelta timeout_duration, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate, - MockClientSocketFactory* client_socket_factory, - NetLog* net_log) + MockClientSocketFactory* client_socket_factory) : ConnectJob(request.priority(), + request.socket_tag(), timeout_duration, - CommonConnectJobParams( - group_name, - request.socket_tag(), - nullptr /* client_socket_factory */, - nullptr /* host_resolver */, - nullptr /* proxy_delegate */, - SSLClientSocketContext(), - SSLClientSocketContext(), - nullptr /* socket_performance_watcher_factory */, - nullptr /* network_quality_estimator */, - net_log, - nullptr /* websocket_endpoint_lock_manager */), + common_connect_job_params, delegate, nullptr /* net_log */, NetLogSourceType::TRANSPORT_CONNECT_JOB, @@ -536,10 +525,19 @@ public: TestConnectJobFactory(MockClientSocketFactory* client_socket_factory, NetLog* net_log) - : job_type_(TestConnectJob::kMockJob), + : common_connect_job_params_( + nullptr /* client_socket_factory */, + nullptr /* host_resolver */, + nullptr /* proxy_delegate */, + SSLClientSocketContext(), + SSLClientSocketContext(), + nullptr /* socket_performance_watcher_factory */, + nullptr /* network_quality_estimator */, + net_log, + nullptr /* websocket_endpoint_lock_manager */), + job_type_(TestConnectJob::kMockJob), job_types_(NULL), - client_socket_factory_(client_socket_factory), - net_log_(net_log) {} + client_socket_factory_(client_socket_factory) {} ~TestConnectJobFactory() override = default; @@ -557,7 +555,6 @@ // ConnectJobFactory implementation. std::unique_ptr<ConnectJob> NewConnectJob( - const std::string& group_name, const TestClientSocketPoolBase::Request& request, ConnectJob::Delegate* delegate) const override { EXPECT_TRUE(!job_types_ || !job_types_->empty()); @@ -566,17 +563,17 @@ job_type = job_types_->front(); job_types_->pop_front(); } - return std::unique_ptr<ConnectJob>( - new TestConnectJob(job_type, group_name, request, timeout_duration_, - delegate, client_socket_factory_, net_log_)); + return std::make_unique<TestConnectJob>( + job_type, request, timeout_duration_, &common_connect_job_params_, + delegate, client_socket_factory_); } private: + const CommonConnectJobParams common_connect_job_params_; TestConnectJob::JobType job_type_; std::list<TestConnectJob::JobType>* job_types_; base::TimeDelta timeout_duration_; MockClientSocketFactory* const client_socket_factory_; - NetLog* net_log_; DISALLOW_COPY_AND_ASSIGN(TestConnectJobFactory); };
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc index 65ff148..c0de62a 100644 --- a/net/socket/client_socket_pool_manager_impl.cc +++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -107,7 +107,6 @@ ssl_client_session_cache_privacy_mode_, ssl_config_service_, network_quality_estimator_, websocket_endpoint_lock_manager_, net_log_); } else { - // TODO(mmenke): Can the SOCKS check be removed? new_pool = std::make_unique<TransportClientSocketPool>( sockets_per_proxy_server, sockets_per_group, unused_idle_socket_timeout(pool_type_), socket_factory_, host_resolver_, @@ -115,8 +114,8 @@ transport_security_state_, cert_transparency_verifier_, ct_policy_enforcer_, ssl_client_session_cache_, ssl_client_session_cache_privacy_mode_, ssl_config_service_, - proxy_server.is_socks() ? nullptr : socket_performance_watcher_factory_, - network_quality_estimator_, net_log_); + socket_performance_watcher_factory_, network_quality_estimator_, + net_log_); } std::pair<TransportSocketPoolMap::iterator, bool> ret =
diff --git a/net/socket/connect_job.cc b/net/socket/connect_job.cc index d87bb38..10ba19b 100644 --- a/net/socket/connect_job.cc +++ b/net/socket/connect_job.cc
@@ -18,8 +18,6 @@ namespace net { CommonConnectJobParams::CommonConnectJobParams( - const std::string& group_name, - const SocketTag& socket_tag, ClientSocketFactory* client_socket_factory, HostResolver* host_resolver, ProxyDelegate* proxy_delegate, @@ -29,9 +27,7 @@ NetworkQualityEstimator* network_quality_estimator, NetLog* net_log, WebSocketEndpointLockManager* websocket_endpoint_lock_manager) - : group_name(group_name), - socket_tag(socket_tag), - client_socket_factory(client_socket_factory), + : client_socket_factory(client_socket_factory), host_resolver(host_resolver), proxy_delegate(proxy_delegate), ssl_client_socket_context(ssl_client_socket_context), @@ -40,9 +36,7 @@ socket_performance_watcher_factory(socket_performance_watcher_factory), network_quality_estimator(network_quality_estimator), net_log(net_log), - websocket_endpoint_lock_manager(websocket_endpoint_lock_manager) { - DCHECK(!group_name.empty()); -} + websocket_endpoint_lock_manager(websocket_endpoint_lock_manager) {} CommonConnectJobParams::CommonConnectJobParams( const CommonConnectJobParams& other) = default; @@ -53,29 +47,27 @@ const CommonConnectJobParams& other) = default; ConnectJob::ConnectJob(RequestPriority priority, + const SocketTag& socket_tag, base::TimeDelta timeout_duration, - const CommonConnectJobParams& common_connect_job_params, + const CommonConnectJobParams* common_connect_job_params, Delegate* delegate, const NetLogWithSource* net_log, NetLogSourceType net_log_source_type, NetLogEventType net_log_connect_event_type) : timeout_duration_(timeout_duration), priority_(priority), + socket_tag_(socket_tag), common_connect_job_params_(common_connect_job_params), delegate_(delegate), top_level_job_(net_log == nullptr), net_log_(net_log ? *net_log - : NetLogWithSource::Make(common_connect_job_params.net_log, + : NetLogWithSource::Make(common_connect_job_params->net_log, net_log_source_type)), net_log_connect_event_type_(net_log_connect_event_type) { DCHECK(delegate); - if (top_level_job_) { - net_log_.BeginEvent( - NetLogEventType::CONNECT_JOB, - NetLog::StringCallback("group_name", - &common_connect_job_params.group_name)); - } + if (top_level_job_) + net_log_.BeginEvent(NetLogEventType::CONNECT_JOB); } ConnectJob::~ConnectJob() {
diff --git a/net/socket/connect_job.h b/net/socket/connect_job.h index 7e54215..49dedfbf 100644 --- a/net/socket/connect_job.h +++ b/net/socket/connect_job.h
@@ -43,8 +43,6 @@ // those. struct NET_EXPORT_PRIVATE CommonConnectJobParams { CommonConnectJobParams( - const std::string& group_name, - const SocketTag& socket_tag, ClientSocketFactory* client_socket_factory, HostResolver* host_resolver, ProxyDelegate* proxy_delegate, @@ -59,14 +57,6 @@ CommonConnectJobParams& operator=(const CommonConnectJobParams& other); - // Socket pool group name, used for logging and identying the group in a - // socket pool. - // TODO(mmenke): Remove the latter use. - std::string group_name; - - // Tag applied to any created socket. - SocketTag socket_tag; - ClientSocketFactory* client_socket_factory; HostResolver* host_resolver; ProxyDelegate* proxy_delegate; @@ -125,8 +115,9 @@ // |net_log_connect_event_type| is the NetLog event type logged on Connect() // and connect completion. ConnectJob(RequestPriority priority, + const SocketTag& socket_tag, base::TimeDelta timeout_duration, - const CommonConnectJobParams& common_connect_job_params, + const CommonConnectJobParams* common_connect_job_params, Delegate* delegate, const NetLogWithSource* net_log, NetLogSourceType net_log_source_type, @@ -134,9 +125,6 @@ virtual ~ConnectJob(); // Accessors - const std::string& group_name() const { - return common_connect_job_params_.group_name; - } const NetLogWithSource& net_log() { return net_log_; } RequestPriority priority() const { return priority_; } @@ -193,31 +181,29 @@ const NetLogWithSource& net_log() const { return net_log_; } protected: - const SocketTag& socket_tag() const { - return common_connect_job_params_.socket_tag; - } + const SocketTag& socket_tag() const { return socket_tag_; } ClientSocketFactory* client_socket_factory() { - return common_connect_job_params_.client_socket_factory; + return common_connect_job_params_->client_socket_factory; } HostResolver* host_resolver() { - return common_connect_job_params_.host_resolver; + return common_connect_job_params_->host_resolver; } const SSLClientSocketContext& ssl_client_socket_context() { - return common_connect_job_params_.ssl_client_socket_context; + return common_connect_job_params_->ssl_client_socket_context; } const SSLClientSocketContext& ssl_client_socket_context_privacy_mode() { - return common_connect_job_params_.ssl_client_socket_context_privacy_mode; + return common_connect_job_params_->ssl_client_socket_context_privacy_mode; } SocketPerformanceWatcherFactory* socket_performance_watcher_factory() { - return common_connect_job_params_.socket_performance_watcher_factory; + return common_connect_job_params_->socket_performance_watcher_factory; } NetworkQualityEstimator* network_quality_estimator() { - return common_connect_job_params_.network_quality_estimator; + return common_connect_job_params_->network_quality_estimator; } WebSocketEndpointLockManager* websocket_endpoint_lock_manager() { - return common_connect_job_params_.websocket_endpoint_lock_manager; + return common_connect_job_params_->websocket_endpoint_lock_manager; } - const CommonConnectJobParams& common_connect_job_params() { + const CommonConnectJobParams* common_connect_job_params() { return common_connect_job_params_; } @@ -245,7 +231,8 @@ const base::TimeDelta timeout_duration_; RequestPriority priority_; - const CommonConnectJobParams common_connect_job_params_; + const SocketTag socket_tag_; + const CommonConnectJobParams* common_connect_job_params_; // Timer to abort jobs that take too long. base::OneShotTimer timer_; Delegate* delegate_;
diff --git a/net/socket/connect_job_unittest.cc b/net/socket/connect_job_unittest.cc index 43ef541..915d02b 100644 --- a/net/socket/connect_job_unittest.cc +++ b/net/socket/connect_job_unittest.cc
@@ -34,22 +34,12 @@ TestConnectJob(JobType job_type, base::TimeDelta timeout_duration, - ConnectJob::Delegate* delegate, - NetLog* net_log) + const CommonConnectJobParams* common_connect_job_params, + ConnectJob::Delegate* delegate) : ConnectJob(DEFAULT_PRIORITY, + SocketTag(), timeout_duration, - CommonConnectJobParams( - "group_name", - SocketTag(), - nullptr /* client_socket_factory */, - nullptr /* host_resolver */, - nullptr /* proxy_delegate */, - SSLClientSocketContext(), - SSLClientSocketContext(), - nullptr /* socket_performance_watcher_factory */, - nullptr /* network_quality_estimator */, - net_log, - nullptr /* websocket_endpoint_lock_manager */), + common_connect_job_params, delegate, nullptr /* net_log */, NetLogSourceType::TRANSPORT_CONNECT_JOB, @@ -88,7 +78,7 @@ // The priority seen during the most recent call to ChangePriorityInternal(). RequestPriority last_seen_priority() const { return last_seen_priority_; } - private: + protected: const JobType job_type_; StaticSocketDataProvider socket_data_provider_; RequestPriority last_seen_priority_; @@ -100,11 +90,23 @@ public: ConnectJobTest() : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {} + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME), + common_connect_job_params_( + nullptr /* client_socket_factory */, + nullptr /* host_resolver */, + nullptr /* proxy_delegate */, + SSLClientSocketContext(), + SSLClientSocketContext(), + nullptr /* socket_performance_watcher_factory */, + nullptr /* network_quality_estimator */, + &net_log_, + nullptr /* websocket_endpoint_lock_manager */) {} ~ConnectJobTest() override = default; protected: base::test::ScopedTaskEnvironment scoped_task_environment_; + TestNetLog net_log_; + const CommonConnectJobParams common_connect_job_params_; TestConnectJobDelegate delegate_; }; @@ -112,8 +114,8 @@ // completion. TEST_F(ConnectJobTest, NoTimeoutOnSyncCompletion) { TestConnectJob job(TestConnectJob::JobType::kSyncSuccess, - base::TimeDelta::FromMicroseconds(1), &delegate_, - nullptr /* net_log */); + base::TimeDelta::FromMicroseconds(1), + &common_connect_job_params_, &delegate_); EXPECT_THAT(job.Connect(), test::IsOk()); } @@ -121,8 +123,8 @@ // completion. TEST_F(ConnectJobTest, NoTimeoutOnAsyncCompletion) { TestConnectJob job(TestConnectJob::JobType::kAsyncSuccess, - base::TimeDelta::FromMinutes(1), &delegate_, - nullptr /* net_log */); + base::TimeDelta::FromMinutes(1), + &common_connect_job_params_, &delegate_); ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING)); EXPECT_THAT(delegate_.WaitForResult(), test::IsOk()); } @@ -130,7 +132,7 @@ // Job shouldn't timeout when passed a TimeDelta of zero. TEST_F(ConnectJobTest, NoTimeoutWithNoTimeDelta) { TestConnectJob job(TestConnectJob::JobType::kHung, base::TimeDelta(), - &delegate_, nullptr /* net_log */); + &common_connect_job_params_, &delegate_); ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING)); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(delegate_.has_result()); @@ -140,8 +142,8 @@ // subclasses during the SetPriorityInternal call. TEST_F(ConnectJobTest, SetPriority) { TestConnectJob job(TestConnectJob::JobType::kAsyncSuccess, - base::TimeDelta::FromMicroseconds(1), &delegate_, - nullptr /* net_log */); + base::TimeDelta::FromMicroseconds(1), + &common_connect_job_params_, &delegate_); ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING)); job.ChangePriority(HIGHEST); @@ -157,10 +159,10 @@ TEST_F(ConnectJobTest, TimedOut) { const base::TimeDelta kTimeout = base::TimeDelta::FromHours(1); - TestNetLog log; - std::unique_ptr<TestConnectJob> job = std::make_unique<TestConnectJob>( - TestConnectJob::JobType::kHung, kTimeout, &delegate_, &log); + std::unique_ptr<TestConnectJob> job = + std::make_unique<TestConnectJob>(TestConnectJob::JobType::kHung, kTimeout, + &common_connect_job_params_, &delegate_); ASSERT_THAT(job->Connect(), test::IsError(ERR_IO_PENDING)); // Nothing should happen before the specified time. @@ -177,7 +179,7 @@ job.reset(); TestNetLogEntry::List entries; - log.GetEntries(&entries); + net_log_.GetEntries(&entries); EXPECT_EQ(6u, entries.size()); EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::CONNECT_JOB)); @@ -197,8 +199,8 @@ TEST_F(ConnectJobTest, TimedOutWithRestartedTimer) { const base::TimeDelta kTimeout = base::TimeDelta::FromHours(1); - TestConnectJob job(TestConnectJob::JobType::kHung, kTimeout, &delegate_, - nullptr /* net_log */); + TestConnectJob job(TestConnectJob::JobType::kHung, kTimeout, + &common_connect_job_params_, &delegate_); ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING)); // Nothing should happen before the specified time.
diff --git a/net/socket/socks_connect_job.cc b/net/socket/socks_connect_job.cc index 60efaec..6f52016 100644 --- a/net/socket/socks_connect_job.cc +++ b/net/socket/socks_connect_job.cc
@@ -36,11 +36,13 @@ SOCKSConnectJob::SOCKSConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<SOCKSSocketParams>& socks_params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log) : ConnectJob(priority, + socket_tag, ConnectionTimeout(), common_connect_job_params, delegate, @@ -138,7 +140,7 @@ next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; transport_connect_job_ = TransportConnectJob::CreateTransportConnectJob( - socks_params_->transport_params(), priority(), + socks_params_->transport_params(), priority(), socket_tag(), common_connect_job_params(), this, &net_log()); return transport_connect_job_->Connect(); }
diff --git a/net/socket/socks_connect_job.h b/net/socket/socks_connect_job.h index 210a930..f043500 100644 --- a/net/socket/socks_connect_job.h +++ b/net/socket/socks_connect_job.h
@@ -20,6 +20,7 @@ namespace net { +class SocketTag; class StreamSocket; class TransportSocketParams; @@ -62,7 +63,8 @@ public ConnectJob::Delegate { public: SOCKSConnectJob(RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<SOCKSSocketParams>& socks_params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log);
diff --git a/net/socket/socks_connect_job_unittest.cc b/net/socket/socks_connect_job_unittest.cc index 2a1062ee..12d6d3a 100644 --- a/net/socket/socks_connect_job_unittest.cc +++ b/net/socket/socks_connect_job_unittest.cc
@@ -49,7 +49,17 @@ : WithScopedTaskEnvironment( base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME, base::test::ScopedTaskEnvironment::NowSource:: - MAIN_THREAD_MOCK_TIME) { + MAIN_THREAD_MOCK_TIME), + common_connect_job_params_( + &client_socket_factory_, + &host_resolver_, + nullptr /* proxy_delegate */, + SSLClientSocketContext(), + SSLClientSocketContext(), + nullptr /* socket_performance_watcher_factory */, + nullptr /* network_quality_estimator */, + &net_log_, + nullptr /* websocket_endpoint_lock_manager */) { // Set an initial delay to ensure that the first call to TimeTicks::Now() // before incrementing the counter does not return a null value. FastForwardBy(base::TimeDelta::FromSeconds(1)); @@ -70,21 +80,11 @@ TRAFFIC_ANNOTATION_FOR_TESTS); } - CommonConnectJobParams CreateCommonParams() { - // Group name doesn't matter. - return CommonConnectJobParams( - "group_name", SocketTag(), &client_socket_factory_, &host_resolver_, - nullptr /* proxy_delegate */, SSLClientSocketContext(), - SSLClientSocketContext(), - nullptr /* socket_performance_watcher_factory */, - nullptr /* network_quality_estimator */, &net_log_, - nullptr /* websocket_endpoint_lock_manager */); - } - protected: NetLog net_log_; MockHostResolver host_resolver_; MockTaggingClientSocketFactory client_socket_factory_; + const CommonConnectJobParams common_connect_job_params_; }; TEST_F(SOCKSConnectJobTest, HostResolutionFailure) { @@ -93,7 +93,8 @@ for (bool failure_synchronous : {false, true}) { host_resolver_.set_synchronous_mode(failure_synchronous); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( @@ -121,7 +122,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( @@ -154,7 +156,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V4), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( @@ -190,7 +193,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( @@ -217,7 +221,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V4), &test_delegate, nullptr /* net_log */); socks_connect_job.Connect(); @@ -247,7 +252,8 @@ host_resolver_.set_ondemand_mode(true); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); socks_connect_job.Connect(); @@ -284,7 +290,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); socks_connect_job.Connect(); @@ -329,9 +336,9 @@ continue; TestConnectJobDelegate test_delegate; SOCKSConnectJob socks_connect_job( - static_cast<RequestPriority>(initial_priority), CreateCommonParams(), - CreateSOCKSParams(SOCKSVersion::V4), &test_delegate, - nullptr /* net_log */); + static_cast<RequestPriority>(initial_priority), SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V4), + &test_delegate, nullptr /* net_log */); ASSERT_THAT(socks_connect_job.Connect(), test::IsError(ERR_IO_PENDING)); ASSERT_TRUE(host_resolver_.has_pending_requests()); int request_id = host_resolver_.num_resolve(); @@ -374,7 +381,8 @@ client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data); TestConnectJobDelegate test_delegate; - SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, CreateCommonParams(), + SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); base::TimeTicks start = base::TimeTicks::Now(); @@ -413,7 +421,8 @@ TestConnectJobDelegate test_delegate; std::unique_ptr<SOCKSConnectJob> socks_connect_job = - std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, CreateCommonParams(), + std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); socks_connect_job->Connect(); @@ -436,7 +445,8 @@ TestConnectJobDelegate test_delegate; std::unique_ptr<SOCKSConnectJob> socks_connect_job = - std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, CreateCommonParams(), + std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); socks_connect_job->Connect(); @@ -464,7 +474,8 @@ TestConnectJobDelegate test_delegate; std::unique_ptr<SOCKSConnectJob> socks_connect_job = - std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, CreateCommonParams(), + std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(), + &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V5), &test_delegate, nullptr /* net_log */); socks_connect_job->Connect();
diff --git a/net/socket/ssl_connect_job.cc b/net/socket/ssl_connect_job.cc index d1e8888..87ab689 100644 --- a/net/socket/ssl_connect_job.cc +++ b/net/socket/ssl_connect_job.cc
@@ -92,14 +92,16 @@ SSLConnectJob::SSLConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<SSLSocketParams>& params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log) : ConnectJob(priority, + socket_tag, ConnectionTimeout( *params, - common_connect_job_params.network_quality_estimator), + common_connect_job_params->network_quality_estimator), common_connect_job_params, delegate, net_log, @@ -268,7 +270,7 @@ next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; nested_connect_job_ = TransportConnectJob::CreateTransportConnectJob( - params_->GetDirectConnectionParams(), priority(), + params_->GetDirectConnectionParams(), priority(), socket_tag(), common_connect_job_params(), this, &net_log()); return nested_connect_job_->Connect(); } @@ -296,7 +298,7 @@ next_state_ = STATE_SOCKS_CONNECT_COMPLETE; nested_connect_job_ = std::make_unique<SOCKSConnectJob>( - priority(), common_connect_job_params(), + priority(), socket_tag(), common_connect_job_params(), params_->GetSocksProxyConnectionParams(), this, &net_log()); return nested_connect_job_->Connect(); } @@ -318,7 +320,7 @@ scoped_refptr<HttpProxySocketParams> http_proxy_params = params_->GetHttpProxyConnectionParams(); nested_connect_job_ = std::make_unique<HttpProxyConnectJob>( - priority(), common_connect_job_params(), + priority(), socket_tag(), common_connect_job_params(), params_->GetHttpProxyConnectionParams(), this, &net_log()); return nested_connect_job_->Connect(); }
diff --git a/net/socket/ssl_connect_job.h b/net/socket/ssl_connect_job.h index d305e38..523f1f8 100644 --- a/net/socket/ssl_connect_job.h +++ b/net/socket/ssl_connect_job.h
@@ -26,6 +26,7 @@ class ClientSocketHandle; class HostPortPair; class HttpProxySocketParams; +class SocketTag; class SOCKSSocketParams; class TransportSocketParams; @@ -82,7 +83,8 @@ // Note: the SSLConnectJob does not own |messenger| so it must outlive the // job. SSLConnectJob(RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<SSLSocketParams>& params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log);
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc index eb684db0..7c31bcd1 100644 --- a/net/socket/ssl_connect_job_unittest.cc +++ b/net/socket/ssl_connect_job_unittest.cc
@@ -53,7 +53,6 @@ const int kMaxSocketsPerGroup = 6; constexpr base::TimeDelta kUnusedIdleSocketTimeout = base::TimeDelta::FromSeconds(10); -const char kGroupName[] = "a"; // Just check that all connect times are set to base::TimeTicks::Now(), for // tests that don't update the mocked out time. @@ -140,7 +139,17 @@ nullptr /* ssl_config_service */, nullptr /* socket_performance_watcher_factory */, nullptr /* network_quality_estimator */, - nullptr /* net_log */) { + nullptr /* net_log */), + common_connect_job_params_( + &socket_factory_, + &host_resolver_, + nullptr /* proxy_delegate */, + ssl_client_socket_context_, + ssl_client_socket_context_, + nullptr /* socket_performance_watcher */, + nullptr /* network_quality_estimator */, + nullptr /* net_log */, + nullptr /* websocket_lock_endpoint_manager */) { ssl_config_service_->GetSSLConfig(&ssl_config_); // Set an initial delay to ensure that the first call to TimeTicks::Now() @@ -155,14 +164,7 @@ ProxyServer::Scheme proxy_scheme = ProxyServer::SCHEME_DIRECT, RequestPriority priority = DEFAULT_PRIORITY) { return std::make_unique<SSLConnectJob>( - priority, - CommonConnectJobParams( - kGroupName, SocketTag(), &socket_factory_, &host_resolver_, - nullptr /* proxy_delegate */, ssl_client_socket_context_, - ssl_client_socket_context_, - nullptr /* socket_performance_watcher */, - nullptr /* network_quality_estimator */, nullptr /* net_log */, - nullptr /* websocket_lock_endpoint_manager */), + priority, SocketTag(), &common_connect_job_params_, SSLParams(proxy_scheme), test_delegate, nullptr /* net_log */); } @@ -223,6 +225,7 @@ TransportClientSocketPool http_proxy_socket_pool_; SSLConfig ssl_config_; + const CommonConnectJobParams common_connect_job_params_; }; TEST_F(SSLConnectJobTest, TCPFail) {
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc index 023d121..2c00e22c 100644 --- a/net/socket/transport_client_socket_pool.cc +++ b/net/socket/transport_client_socket_pool.cc
@@ -36,41 +36,45 @@ std::unique_ptr<ConnectJob> CreateTransportConnectJob( scoped_refptr<TransportSocketParams> transport_socket_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate) { return TransportConnectJob::CreateTransportConnectJob( - std::move(transport_socket_params), priority, common_connect_job_params, - delegate, nullptr /* net_log */); + std::move(transport_socket_params), priority, socket_tag, + common_connect_job_params, delegate, nullptr /* net_log */); } std::unique_ptr<ConnectJob> CreateSOCKSConnectJob( scoped_refptr<SOCKSSocketParams> socks_socket_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate) { - return std::make_unique<SOCKSConnectJob>(priority, common_connect_job_params, - std::move(socks_socket_params), - delegate, nullptr /* net_log */); + return std::make_unique<SOCKSConnectJob>( + priority, socket_tag, common_connect_job_params, + std::move(socks_socket_params), delegate, nullptr /* net_log */); } std::unique_ptr<ConnectJob> CreateSSLConnectJob( scoped_refptr<SSLSocketParams> ssl_socket_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate) { - return std::make_unique<SSLConnectJob>(priority, common_connect_job_params, - std::move(ssl_socket_params), delegate, - nullptr /* net_log */); + return std::make_unique<SSLConnectJob>( + priority, socket_tag, common_connect_job_params, + std::move(ssl_socket_params), delegate, nullptr /* net_log */); } std::unique_ptr<ConnectJob> CreateHttpProxyConnectJob( scoped_refptr<HttpProxySocketParams> http_proxy_socket_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate) { return std::make_unique<HttpProxyConnectJob>( - priority, common_connect_job_params, std::move(http_proxy_socket_params), - delegate, nullptr /* net_log */); + priority, socket_tag, common_connect_job_params, + std::move(http_proxy_socket_params), delegate, nullptr /* net_log */); } } // namespace @@ -123,32 +127,26 @@ SocketPerformanceWatcherFactory* socket_performance_watcher_factory, NetworkQualityEstimator* network_quality_estimator, NetLog* net_log) - : client_socket_factory_(client_socket_factory), - host_resolver_(host_resolver), - proxy_delegate_(proxy_delegate), - ssl_client_socket_context_(ssl_client_socket_context), - ssl_client_socket_context_privacy_mode_( - ssl_client_socket_context_privacy_mode), - socket_performance_watcher_factory_(socket_performance_watcher_factory), - network_quality_estimator_(network_quality_estimator), - net_log_(net_log) {} + : common_connect_job_params_( + client_socket_factory, + host_resolver, + proxy_delegate, + ssl_client_socket_context, + ssl_client_socket_context_privacy_mode, + socket_performance_watcher_factory, + network_quality_estimator, + net_log, + nullptr /* websocket_endpoint_lock_manager */) {} TransportClientSocketPool::TransportConnectJobFactory:: ~TransportConnectJobFactory() = default; std::unique_ptr<ConnectJob> TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob( - const std::string& group_name, const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { return request.params()->create_connect_job_callback().Run( - request.priority(), - CommonConnectJobParams( - group_name, request.socket_tag(), - client_socket_factory_, host_resolver_, proxy_delegate_, - ssl_client_socket_context_, ssl_client_socket_context_privacy_mode_, - socket_performance_watcher_factory_, network_quality_estimator_, - net_log_, nullptr /* websocket_endpoint_lock_manager */), + request.priority(), request.socket_tag(), &common_connect_job_params_, delegate); }
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h index 7197460..e8aa4873 100644 --- a/net/socket/transport_client_socket_pool.h +++ b/net/socket/transport_client_socket_pool.h
@@ -14,6 +14,7 @@ #include "net/base/net_export.h" #include "net/socket/client_socket_pool.h" #include "net/socket/client_socket_pool_base.h" +#include "net/socket/connect_job.h" #include "net/socket/connection_attempts.h" #include "net/socket/socket_tag.h" #include "net/socket/ssl_client_socket.h" @@ -50,7 +51,8 @@ using CreateConnectJobCallback = base::RepeatingCallback<std::unique_ptr<ConnectJob>( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate)>; // "Parameters" that own a single callback for creating a ConnectJob that can @@ -181,19 +183,11 @@ // ClientSocketPoolBase::ConnectJobFactory methods. std::unique_ptr<ConnectJob> NewConnectJob( - const std::string& group_name, const PoolBase::Request& request, ConnectJob::Delegate* delegate) const override; private: - ClientSocketFactory* const client_socket_factory_; - HostResolver* const host_resolver_; - ProxyDelegate* const proxy_delegate_; - const SSLClientSocketContext ssl_client_socket_context_; - const SSLClientSocketContext ssl_client_socket_context_privacy_mode_; - SocketPerformanceWatcherFactory* const socket_performance_watcher_factory_; - NetworkQualityEstimator* const network_quality_estimator_; - NetLog* const net_log_; + const CommonConnectJobParams common_connect_job_params_; DISALLOW_COPY_AND_ASSIGN(TransportConnectJobFactory); };
diff --git a/net/socket/transport_connect_job.cc b/net/socket/transport_connect_job.cc index d2d612e..1b6d525 100644 --- a/net/socket/transport_connect_job.cc +++ b/net/socket/transport_connect_job.cc
@@ -70,27 +70,30 @@ std::unique_ptr<ConnectJob> TransportConnectJob::CreateTransportConnectJob( scoped_refptr<TransportSocketParams> transport_client_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log) { - if (!common_connect_job_params.websocket_endpoint_lock_manager) { + if (!common_connect_job_params->websocket_endpoint_lock_manager) { return std::make_unique<TransportConnectJob>( - priority, common_connect_job_params, transport_client_params, delegate, - net_log); + priority, socket_tag, common_connect_job_params, + transport_client_params, delegate, net_log); } return std::make_unique<WebSocketTransportConnectJob>( - priority, common_connect_job_params, transport_client_params, delegate, - net_log); + priority, socket_tag, common_connect_job_params, transport_client_params, + delegate, net_log); } TransportConnectJob::TransportConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log) : ConnectJob(priority, + socket_tag, ConnectionTimeout(), common_connect_job_params, delegate, @@ -101,7 +104,7 @@ next_state_(STATE_NONE), resolve_result_(OK) { // This is only set for WebSockets. - DCHECK(!common_connect_job_params.websocket_endpoint_lock_manager); + DCHECK(!common_connect_job_params->websocket_endpoint_lock_manager); } TransportConnectJob::~TransportConnectJob() {
diff --git a/net/socket/transport_connect_job.h b/net/socket/transport_connect_job.h index ff8af775..f6bc4fc 100644 --- a/net/socket/transport_connect_job.h +++ b/net/socket/transport_connect_job.h
@@ -22,6 +22,7 @@ namespace net { class NetLogWithSource; +class SocketTag; typedef base::RepeatingCallback<int(const AddressList&, const NetLogWithSource& net_log)> @@ -90,12 +91,14 @@ static std::unique_ptr<ConnectJob> CreateTransportConnectJob( scoped_refptr<TransportSocketParams> transport_client_params, RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log); TransportConnectJob(RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log);
diff --git a/net/socket/transport_connect_job_unittest.cc b/net/socket/transport_connect_job_unittest.cc index 8cb2aa76..0fbc0a6 100644 --- a/net/socket/transport_connect_job_unittest.cc +++ b/net/socket/transport_connect_job_unittest.cc
@@ -31,7 +31,18 @@ class TransportConnectJobTest : public TestWithScopedTaskEnvironment { public: - TransportConnectJobTest() : client_socket_factory_(&net_log_) {} + TransportConnectJobTest() + : client_socket_factory_(&net_log_), + common_connect_job_params_( + &client_socket_factory_, + &host_resolver_, + nullptr /* proxy_delegate */, + SSLClientSocketContext(), + SSLClientSocketContext(), + nullptr /* socket_performance_watcher_factory */, + nullptr /* network_quality_estimator */, + &net_log_, + nullptr /* websocket_endpoint_lock_manager */) {} ~TransportConnectJobTest() override {} @@ -40,20 +51,11 @@ HostPortPair(kHostName, 80), false, OnHostResolutionCallback()); } - CommonConnectJobParams DefaultCommonConnectJobParams() { - return CommonConnectJobParams( - kHostName /* group_name */, SocketTag(), &client_socket_factory_, - &host_resolver_, nullptr /* proxy_delegate */, SSLClientSocketContext(), - SSLClientSocketContext(), - nullptr /* socket_performance_watcher_factory */, - nullptr /* network_quality_estimator */, &net_log_, - nullptr /* websocket_endpoint_lock_manager */); - } - protected: TestNetLog net_log_; MockHostResolver host_resolver_; MockTransportClientSocketFactory client_socket_factory_; + const CommonConnectJobParams common_connect_job_params_; }; TEST_F(TransportConnectJobTest, MakeAddrListStartWithIPv4) { @@ -133,8 +135,8 @@ host_resolver_.set_synchronous_mode(host_resolution_synchronous); TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult(&transport_conect_job, ERR_NAME_NOT_RESOLVED, host_resolution_synchronous); @@ -153,8 +155,8 @@ ClientSocketHandle handle; TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( &transport_conect_job, ERR_CONNECTION_FAILED, host_resolution_synchronous && connection_synchronous); @@ -173,8 +175,8 @@ ClientSocketHandle handle; TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult( &transport_conect_job, OK, host_resolution_synchronous && connection_synchronous); @@ -200,8 +202,8 @@ TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult(&transport_conect_job, OK, false /* expect_sync_result */); @@ -240,8 +242,8 @@ TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult(&transport_conect_job, OK, false /* expect_sync_result */); @@ -270,8 +272,8 @@ TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult(&transport_conect_job, OK, false /* expect_sync_result */); @@ -293,8 +295,8 @@ TestConnectJobDelegate test_delegate; TransportConnectJob transport_conect_job( - DEFAULT_PRIORITY, DefaultCommonConnectJobParams(), DefaultParams(), - &test_delegate, nullptr /* net_log */); + DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_, + DefaultParams(), &test_delegate, nullptr /* net_log */); test_delegate.StartJobExpectingResult(&transport_conect_job, OK, false /* expect_sync_result */);
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc index 28001117..4a5c6d0f 100644 --- a/net/socket/websocket_transport_client_socket_pool.cc +++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -62,25 +62,26 @@ nullptr /* socket_performance_watcher_factory */, network_quality_estimator, net_log), - pool_net_log_(net_log), - client_socket_factory_(client_socket_factory), - host_resolver_(host_resolver), - proxy_delegate_(proxy_delegate), - ssl_client_socket_context_(cert_verifier, + common_connect_job_params_( + client_socket_factory, + host_resolver, + proxy_delegate, + SSLClientSocketContext(cert_verifier, channel_id_service, transport_security_state, cert_transparency_verifier, ct_policy_enforcer, ssl_client_session_cache), - ssl_client_socket_context_privacy_mode_( - cert_verifier, - channel_id_service, - transport_security_state, - cert_transparency_verifier, - ct_policy_enforcer, - ssl_client_session_cache_privacy_mode), - network_quality_estimator_(network_quality_estimator), - websocket_endpoint_lock_manager_(websocket_endpoint_lock_manager), + SSLClientSocketContext(cert_verifier, + channel_id_service, + transport_security_state, + cert_transparency_verifier, + ct_policy_enforcer, + ssl_client_session_cache_privacy_mode), + nullptr /* SocketPerformanceWatcherFactory */, + network_quality_estimator, + net_log, + websocket_endpoint_lock_manager), max_sockets_(max_sockets), handed_out_socket_count_(0), flushing_(false), @@ -156,14 +157,7 @@ // pool types on top of a standard TransportClientSocketPool. std::unique_ptr<ConnectJob> connect_job = casted_params->create_connect_job_callback().Run( - priority, - CommonConnectJobParams(group_name, SocketTag(), - client_socket_factory_, host_resolver_, - proxy_delegate_, ssl_client_socket_context_, - ssl_client_socket_context_privacy_mode_, - nullptr /* SocketPerformanceWatcherFactory */, - network_quality_estimator_, pool_net_log_, - websocket_endpoint_lock_manager_), + priority, SocketTag(), &common_connect_job_params_, connect_job_delegate.get()); int result = connect_job_delegate->Connect(std::move(connect_job));
diff --git a/net/socket/websocket_transport_client_socket_pool.h b/net/socket/websocket_transport_client_socket_pool.h index a740386..4fe0252 100644 --- a/net/socket/websocket_transport_client_socket_pool.h +++ b/net/socket/websocket_transport_client_socket_pool.h
@@ -21,6 +21,7 @@ #include "net/log/net_log_with_source.h" #include "net/socket/client_socket_pool.h" #include "net/socket/client_socket_pool_base.h" +#include "net/socket/connect_job.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/transport_client_socket_pool.h" @@ -200,18 +201,11 @@ void ActivateStalledRequest(); bool DeleteStalledRequest(ClientSocketHandle* handle); + const CommonConnectJobParams common_connect_job_params_; std::set<const ClientSocketHandle*> pending_callbacks_; PendingConnectsMap pending_connects_; StalledRequestQueue stalled_request_queue_; StalledRequestMap stalled_request_map_; - NetLog* const pool_net_log_; - ClientSocketFactory* const client_socket_factory_; - HostResolver* const host_resolver_; - ProxyDelegate* const proxy_delegate_; - const SSLClientSocketContext ssl_client_socket_context_; - const SSLClientSocketContext ssl_client_socket_context_privacy_mode_; - NetworkQualityEstimator* const network_quality_estimator_; - WebSocketEndpointLockManager* websocket_endpoint_lock_manager_; const int max_sockets_; int handed_out_socket_count_; bool flushing_;
diff --git a/net/socket/websocket_transport_connect_job.cc b/net/socket/websocket_transport_connect_job.cc index 4f9e9be..0c15fb7 100644 --- a/net/socket/websocket_transport_connect_job.cc +++ b/net/socket/websocket_transport_connect_job.cc
@@ -23,11 +23,13 @@ WebSocketTransportConnectJob::WebSocketTransportConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log) : ConnectJob(priority, + socket_tag, TransportConnectJob::ConnectionTimeout(), common_connect_job_params, delegate, @@ -39,7 +41,7 @@ race_result_(TransportConnectJob::RACE_UNKNOWN), had_ipv4_(false), had_ipv6_(false) { - DCHECK(common_connect_job_params.websocket_endpoint_lock_manager); + DCHECK(common_connect_job_params->websocket_endpoint_lock_manager); } WebSocketTransportConnectJob::~WebSocketTransportConnectJob() = default;
diff --git a/net/socket/websocket_transport_connect_job.h b/net/socket/websocket_transport_connect_job.h index 57a7660f..1ebf709d 100644 --- a/net/socket/websocket_transport_connect_job.h +++ b/net/socket/websocket_transport_connect_job.h
@@ -20,6 +20,7 @@ namespace net { +class SocketTag; class WebSocketTransportConnectSubJob; // WebSocketTransportConnectJob handles the host resolution necessary for socket @@ -39,7 +40,8 @@ public: WebSocketTransportConnectJob( RequestPriority priority, - const CommonConnectJobParams& common_connect_job_params, + const SocketTag& socket_tag, + const CommonConnectJobParams* common_connect_job_params, const scoped_refptr<TransportSocketParams>& params, Delegate* delegate, const NetLogWithSource* net_log);
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 6a6171e..7115c81 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -86,7 +86,8 @@ base::WeakPtr<SpdySession> CreateSpdyProxySession( HttpNetworkSession* http_session, SpdySessionDependencies* session_deps, - const SpdySessionKey& key) { + const SpdySessionKey& key, + const CommonConnectJobParams* common_connect_job_params) { EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession( key, true /* enable_ip_based_pooling */, false /* is_websocket */, NetLogWithSource())); @@ -100,27 +101,9 @@ transport_params, nullptr, nullptr, key.host_port_pair(), ssl_config, key.privacy_mode()); TestConnectJobDelegate connect_job_delegate; - SSLConnectJob connect_job( - MEDIUM, - CommonConnectJobParams( - "group_name", SocketTag(), session_deps->socket_factory.get(), - session_deps->host_resolver.get(), nullptr /* proxy_delegate */, - SSLClientSocketContext(session_deps->cert_verifier.get(), - session_deps->channel_id_service.get(), - session_deps->transport_security_state.get(), - session_deps->cert_transparency_verifier.get(), - session_deps->ct_policy_enforcer.get(), - nullptr /* ssl_client_session_cache_arg */), - SSLClientSocketContext(session_deps->cert_verifier.get(), - session_deps->channel_id_service.get(), - session_deps->transport_security_state.get(), - session_deps->cert_transparency_verifier.get(), - session_deps->ct_policy_enforcer.get(), - nullptr /* ssl_client_session_cache_arg */), - nullptr /* socket_performance_watcher_factory */, - nullptr /* network_quality_estimator */, session_deps->net_log, - nullptr /* websocket_endpoint_lock_manager */), - ssl_params, &connect_job_delegate, nullptr /* net_log */); + SSLConnectJob connect_job(MEDIUM, SocketTag(), common_connect_job_params, + ssl_params, &connect_job_delegate, + nullptr /* net_log */); connect_job_delegate.StartJobExpectingResult(&connect_job, OK, false /* expect_sync_result */); @@ -216,6 +199,7 @@ HostPortPair endpoint_host_port_pair_; ProxyServer proxy_; SpdySessionKey endpoint_spdy_session_key_; + const CommonConnectJobParams common_connect_job_params_; DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest); }; @@ -232,7 +216,27 @@ proxy_, PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse, - SocketTag()) { + SocketTag()), + common_connect_job_params_( + session_deps_.socket_factory.get(), + session_deps_.host_resolver.get(), + nullptr /* proxy_delegate */, + SSLClientSocketContext(session_deps_.cert_verifier.get(), + session_deps_.channel_id_service.get(), + session_deps_.transport_security_state.get(), + session_deps_.cert_transparency_verifier.get(), + session_deps_.ct_policy_enforcer.get(), + nullptr /* ssl_client_session_cache_arg */), + SSLClientSocketContext(session_deps_.cert_verifier.get(), + session_deps_.channel_id_service.get(), + session_deps_.transport_security_state.get(), + session_deps_.cert_transparency_verifier.get(), + session_deps_.ct_policy_enforcer.get(), + nullptr /* ssl_client_session_cache_arg */), + nullptr /* socket_performance_watcher_factory */, + nullptr /* network_quality_estimator */, + net_log_.bound().net_log(), + nullptr /* websocket_endpoint_lock_manager */) { session_deps_.net_log = net_log_.bound().net_log(); } @@ -268,7 +272,8 @@ // Creates the SPDY session and stream. spdy_session_ = CreateSpdyProxySession(session_.get(), &session_deps_, - endpoint_spdy_session_key_); + endpoint_spdy_session_key_, + &common_connect_job_params_); base::WeakPtr<SpdyStream> spdy_stream( CreateStreamSynchronously(
diff --git a/net/third_party/quic/core/chlo_extractor.cc b/net/third_party/quic/core/chlo_extractor.cc index 1c81946f..cd7fed4 100644 --- a/net/third_party/quic/core/chlo_extractor.cc +++ b/net/third_party/quic/core/chlo_extractor.cc
@@ -294,8 +294,10 @@ bool ChloExtractor::Extract(const QuicEncryptedPacket& packet, const ParsedQuicVersionVector& versions, const QuicTagVector& create_session_tag_indicators, - Delegate* delegate) { - QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER); + Delegate* delegate, + uint8_t connection_id_length) { + QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER, + connection_id_length); ChloFramerVisitor visitor(&framer, create_session_tag_indicators, delegate); framer.set_visitor(&visitor); if (!framer.ProcessPacket(packet)) {
diff --git a/net/third_party/quic/core/chlo_extractor.h b/net/third_party/quic/core/chlo_extractor.h index 8b07107..e46a646 100644 --- a/net/third_party/quic/core/chlo_extractor.h +++ b/net/third_party/quic/core/chlo_extractor.h
@@ -33,7 +33,8 @@ static bool Extract(const QuicEncryptedPacket& packet, const ParsedQuicVersionVector& versions, const QuicTagVector& create_session_tag_indicators, - Delegate* delegate); + Delegate* delegate, + uint8_t connection_id_length); ChloExtractor(const ChloExtractor&) = delete; ChloExtractor operator=(const ChloExtractor&) = delete;
diff --git a/net/third_party/quic/core/chlo_extractor_test.cc b/net/third_party/quic/core/chlo_extractor_test.cc index c183f1f05..e96b2ca 100644 --- a/net/third_party/quic/core/chlo_extractor_test.cc +++ b/net/third_party/quic/core/chlo_extractor_test.cc
@@ -69,7 +69,7 @@ offset++; } QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), - Perspective::IS_CLIENT); + Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); if (version.transport_version < QUIC_VERSION_47 || munge_stream_id) { QuicStreamId stream_id = QuicUtils::GetCryptoStreamId(version.transport_version); @@ -121,7 +121,8 @@ } MakePacket(version, client_hello_str, /*munge_offset*/ false, /*munge_stream_id*/ false); - EXPECT_TRUE(ChloExtractor::Extract(*packet_, versions, {}, &delegate_)) + EXPECT_TRUE(ChloExtractor::Extract(*packet_, versions, {}, &delegate_, + kQuicDefaultConnectionIdLength)) << ParsedQuicVersionToString(version); EXPECT_EQ(version.transport_version, delegate_.transport_version()); EXPECT_EQ(header_.destination_connection_id, delegate_.connection_id()); @@ -137,8 +138,9 @@ QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); MakePacket(AllSupportedVersions()[0], client_hello_str, /*munge_offset*/ false, /*munge_stream_id*/ true); - EXPECT_FALSE( - ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, + &delegate_, + kQuicDefaultConnectionIdLength)); } TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { @@ -148,15 +150,17 @@ QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); MakePacket(AllSupportedVersions()[0], client_hello_str, /*munge_offset*/ true, /*munge_stream_id*/ false); - EXPECT_FALSE( - ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, + &delegate_, + kQuicDefaultConnectionIdLength)); } TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { MakePacket(AllSupportedVersions()[0], "foo", /*munge_offset*/ false, /*munge_stream_id*/ true); - EXPECT_FALSE( - ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, + &delegate_, + kQuicDefaultConnectionIdLength)); } } // namespace
diff --git a/net/third_party/quic/core/congestion_control/bbr_sender_test.cc b/net/third_party/quic/core/congestion_control/bbr_sender_test.cc index 313725d..e80a35a8b 100644 --- a/net/third_party/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/third_party/quic/core/congestion_control/bbr_sender_test.cc
@@ -256,8 +256,7 @@ // Test a simple long data transfer in the default setup. TEST_F(BbrSenderTest, SimpleTransfer) { // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); // At startup make sure we are at the default. @@ -306,8 +305,7 @@ // congestion_window_ in GetCongestionWindow(). SetConnectionOption(kBBS1); // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); // At startup make sure we are at the default. @@ -377,7 +375,7 @@ QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_); // Enable Ack Decimation on the receiver. QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::ACK_DECIMATION); + AckMode::ACK_DECIMATION); CreateDefaultSetup(); // Transfer 12MB. @@ -402,8 +400,7 @@ // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBR4); // 2 RTTs of aggregation, with a max of 10kb. @@ -430,8 +427,7 @@ // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBR5); // 2 RTTs of aggregation, with a max of 10kb. @@ -546,8 +542,7 @@ // Verify that the DRAIN phase works correctly. TEST_F(BbrSenderTest, Drain) { // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); // Get the queue at the bottleneck, which is the outgoing queue at the port to @@ -610,8 +605,7 @@ TEST_F(BbrSenderTest, ShallowDrain) { SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); // BBQ4 increases the pacing gain in DRAIN to 0.75 @@ -816,8 +810,7 @@ // connection will exit low gain early if the number of bytes in flight is low. TEST_F(BbrSenderTest, InFlightAwareGainCycling) { // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); DriveOutOfStartup(); @@ -1222,8 +1215,7 @@ SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Disable Ack Decimation on the receiver to avoid loss and make results // consistent. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - QuicConnection::AckMode::TCP_ACKING); + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBQ3);
diff --git a/net/third_party/quic/core/crypto/common_cert_set.cc b/net/third_party/quic/core/crypto/common_cert_set.cc index e81d111b..365c3b5 100644 --- a/net/third_party/quic/core/crypto/common_cert_set.cc +++ b/net/third_party/quic/core/crypto/common_cert_set.cc
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_arraysize.h" -#include "net/third_party/quic/platform/api/quic_singleton.h" namespace quic { @@ -142,17 +141,10 @@ return false; } - static CommonCertSetsQUIC* GetInstance() { - return QuicSingleton<CommonCertSetsQUIC>::get(); - } - - private: CommonCertSetsQUIC() {} CommonCertSetsQUIC(const CommonCertSetsQUIC&) = delete; CommonCertSetsQUIC& operator=(const CommonCertSetsQUIC&) = delete; ~CommonCertSetsQUIC() override {} - - friend QuicSingletonFriend<CommonCertSetsQUIC>; }; } // anonymous namespace @@ -161,7 +153,8 @@ // static const CommonCertSets* CommonCertSets::GetInstanceQUIC() { - return CommonCertSetsQUIC::GetInstance(); + static CommonCertSetsQUIC* certs = new CommonCertSetsQUIC(); + return certs; } } // namespace quic
diff --git a/net/third_party/quic/core/crypto/crypto_protocol.h b/net/third_party/quic/core/crypto/crypto_protocol.h index 43499d2..e8df065 100644 --- a/net/third_party/quic/core/crypto/crypto_protocol.h +++ b/net/third_party/quic/core/crypto/crypto_protocol.h
@@ -128,7 +128,6 @@ const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe const QuicTag k1TLP = TAG('1', 'T', 'L', 'P'); // 1 tail loss probe const QuicTag k1RTO = TAG('1', 'R', 'T', 'O'); // Send 1 packet upon RTO -const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection const QuicTag kATIM = TAG('A', 'T', 'I', 'M'); // Adaptive time loss detection
diff --git a/net/third_party/quic/core/crypto/quic_random.cc b/net/third_party/quic/core/crypto/quic_random.cc index ff19d9c..0a4bd4a 100644 --- a/net/third_party/quic/core/crypto/quic_random.cc +++ b/net/third_party/quic/core/crypto/quic_random.cc
@@ -6,7 +6,6 @@ #include "base/macros.h" #include "net/third_party/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quic/platform/api/quic_singleton.h" #include "third_party/boringssl/src/include/openssl/rand.h" namespace quic { @@ -15,25 +14,16 @@ class DefaultRandom : public QuicRandom { public: - static DefaultRandom* GetInstance(); - - // QuicRandom implementation - void RandBytes(void* data, size_t len) override; - uint64_t RandUint64() override; - - private: DefaultRandom() {} DefaultRandom(const DefaultRandom&) = delete; DefaultRandom& operator=(const DefaultRandom&) = delete; ~DefaultRandom() override {} - friend QuicSingletonFriend<DefaultRandom>; + // QuicRandom implementation + void RandBytes(void* data, size_t len) override; + uint64_t RandUint64() override; }; -DefaultRandom* DefaultRandom::GetInstance() { - return QuicSingleton<DefaultRandom>::get(); -} - void DefaultRandom::RandBytes(void* data, size_t len) { RAND_bytes(reinterpret_cast<uint8_t*>(data), len); } @@ -48,7 +38,8 @@ // static QuicRandom* QuicRandom::GetInstance() { - return DefaultRandom::GetInstance(); + static DefaultRandom* random = new DefaultRandom(); + return random; } } // namespace quic
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc index 6cc4a659..882aa1f0 100644 --- a/net/third_party/quic/core/http/end_to_end_test.cc +++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -450,9 +450,13 @@ SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, GetParam().use_cheap_stateless_reject); - auto* test_server = new QuicTestServer( - crypto_test_utils::ProofSourceForTesting(), server_config_, - server_supported_versions_, &memory_cache_backend_); + uint8_t connection_id_length = override_connection_id_ != nullptr + ? override_connection_id_->length() + : kQuicDefaultConnectionIdLength; + auto* test_server = + new QuicTestServer(crypto_test_utils::ProofSourceForTesting(), + server_config_, server_supported_versions_, + &memory_cache_backend_, connection_id_length); server_thread_ = QuicMakeUnique<ServerThread>(test_server, server_address_); if (chlo_multiplier_ != 0) { server_thread_->server()->SetChloMultiplier(chlo_multiplier_); @@ -786,6 +790,18 @@ EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } +TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) { + QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId( + GetParam().negotiated_version.transport_version); + override_connection_id_ = &connection_id; + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + TEST_P(EndToEndTestWithTls, MultipleStreams) { // Verifies quic_test_client can track responses of all active streams. ASSERT_TRUE(Initialize()); @@ -2231,7 +2247,7 @@ QuicPublicResetPacket header; header.connection_id = connection_id; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), - Perspective::IS_SERVER); + Perspective::IS_SERVER, kQuicDefaultConnectionIdLength); std::unique_ptr<QuicEncryptedPacket> packet; if (client_connection->transport_version() > QUIC_VERSION_43) { packet = framer.BuildIetfStatelessResetPacket(connection_id, @@ -2277,7 +2293,7 @@ QuicPublicResetPacket header; header.connection_id = incorrect_connection_id; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), - Perspective::IS_SERVER); + Perspective::IS_SERVER, kQuicDefaultConnectionIdLength); std::unique_ptr<QuicEncryptedPacket> packet; testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; client_->client()->client_session()->connection()->set_debug_visitor( @@ -2328,7 +2344,7 @@ QuicPublicResetPacket header; header.connection_id = incorrect_connection_id; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), - Perspective::IS_CLIENT); + Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); std::unique_ptr<QuicEncryptedPacket> packet( framer.BuildPublicResetPacket(header)); client_writer_->WritePacket(
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc index 848231b9..c411c5c 100644 --- a/net/third_party/quic/core/quic_connection.cc +++ b/net/third_party/quic/core/quic_connection.cc
@@ -223,7 +223,8 @@ const ParsedQuicVersionVector& supported_versions) : framer_(supported_versions, helper->GetClock()->ApproximateNow(), - perspective), + perspective, + connection_id.length()), current_packet_content_(NO_FRAMES_RECEIVED), is_current_packet_connectivity_probing_(false), current_effective_peer_migration_type_(NO_CHANGE), @@ -350,6 +351,9 @@ if (packet_generator_.deprecate_ack_bundling_mode()) { QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_ack_bundling_mode); } + if (received_packet_manager_.decide_when_to_send_acks()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_rpm_decides_when_to_send_acks); + } QUIC_DLOG(INFO) << ENDPOINT << "Created connection with connection_id: " << connection_id << " and version: " @@ -431,29 +435,33 @@ if (debug_visitor_ != nullptr) { debug_visitor_->OnSetFromConfig(config); } - if (GetQuicReloadableFlag(quic_enable_ack_decimation) && - config.HasClientSentConnectionOption(kACD0, perspective_)) { - ack_mode_ = TCP_ACKING; - } - if (config.HasClientSentConnectionOption(kACKD, perspective_)) { - ack_mode_ = ACK_DECIMATION; - } - if (config.HasClientSentConnectionOption(kAKD2, perspective_)) { - ack_mode_ = ACK_DECIMATION_WITH_REORDERING; - } - if (config.HasClientSentConnectionOption(kAKD3, perspective_)) { - ack_mode_ = ACK_DECIMATION; - ack_decimation_delay_ = kShortAckDecimationDelay; - } - if (config.HasClientSentConnectionOption(kAKD4, perspective_)) { - ack_mode_ = ACK_DECIMATION_WITH_REORDERING; - ack_decimation_delay_ = kShortAckDecimationDelay; - } - if (config.HasClientSentConnectionOption(kAKDU, perspective_)) { - unlimited_ack_decimation_ = true; - } - if (config.HasClientSentConnectionOption(kACKQ, perspective_)) { - fast_ack_after_quiescence_ = true; + if (received_packet_manager_.decide_when_to_send_acks()) { + received_packet_manager_.SetFromConfig(config, perspective_); + } else { + if (GetQuicReloadableFlag(quic_enable_ack_decimation) && + config.HasClientSentConnectionOption(kACD0, perspective_)) { + ack_mode_ = TCP_ACKING; + } + if (config.HasClientSentConnectionOption(kACKD, perspective_)) { + ack_mode_ = ACK_DECIMATION; + } + if (config.HasClientSentConnectionOption(kAKD2, perspective_)) { + ack_mode_ = ACK_DECIMATION_WITH_REORDERING; + } + if (config.HasClientSentConnectionOption(kAKD3, perspective_)) { + ack_mode_ = ACK_DECIMATION; + ack_decimation_delay_ = kShortAckDecimationDelay; + } + if (config.HasClientSentConnectionOption(kAKD4, perspective_)) { + ack_mode_ = ACK_DECIMATION_WITH_REORDERING; + ack_decimation_delay_ = kShortAckDecimationDelay; + } + if (config.HasClientSentConnectionOption(kAKDU, perspective_)) { + unlimited_ack_decimation_ = true; + } + if (config.HasClientSentConnectionOption(kACKQ, perspective_)) { + fast_ack_after_quiescence_ = true; + } } if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { close_connection_after_five_rtos_ = true; @@ -515,10 +523,6 @@ return sent_packet_manager_.MaxPacingRate(); } -void QuicConnection::SetNumOpenStreams(size_t num_streams) { - sent_packet_manager_.SetNumOpenStreams(num_streams); -} - bool QuicConnection::SelectMutualVersion( const ParsedQuicVersionVector& available_versions) { // Try to find the highest mutual version by iterating over supported @@ -1431,9 +1435,15 @@ const bool was_missing = should_last_packet_instigate_acks_ && was_last_packet_missing_; - // It's possible the ack frame was sent along with response data, so it - // no longer needs to be sent. - if (ack_frame_updated()) { + if (received_packet_manager_.decide_when_to_send_acks()) { + received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks_, last_header_.packet_number, + time_of_last_received_packet_, clock_->ApproximateNow(), + sent_packet_manager_.GetRttStats(), + sent_packet_manager_.delayed_ack_time()); + } else if (ack_frame_updated()) { + // It's possible the ack frame was sent along with response data, so it + // no longer needs to be sent. MaybeQueueAck(was_missing); } @@ -1457,6 +1467,7 @@ } void QuicConnection::MaybeQueueAck(bool was_missing) { + DCHECK(!received_packet_manager_.decide_when_to_send_acks()); ++num_packets_received_since_last_ack_sent_; // Determine whether the newly received packet was missing before recording // the received packet. @@ -1883,7 +1894,16 @@ ScopedPacketFlusher flusher(this, NO_ACK); WriteQueuedPackets(); - if (send_ack_when_on_can_write_) { + if (received_packet_manager_.decide_when_to_send_acks()) { + const QuicTime ack_timeout = received_packet_manager_.ack_timeout(); + if (ack_timeout.IsInitialized() && + ack_timeout <= clock_->ApproximateNow()) { + // Send an ACK now because either 1) we were write blocked when we last + // tried to send an ACK, or 2) both ack alarm and send alarm were set to + // go off together. + SendAck(); + } + } else if (send_ack_when_on_can_write_) { // Send an ACK now because either 1) we were write blocked when we last // tried to send an ACK, or 2) both ack alarm and send alarm were set to go // off together. @@ -2164,7 +2184,13 @@ const QuicFrames QuicConnection::MaybeBundleAckOpportunistically() { DCHECK(packet_generator_.deprecate_ack_bundling_mode()); QuicFrames frames; - if (!ack_alarm_->IsSet() && stop_waiting_count_ <= 1) { + bool has_pending_ack = false; + if (received_packet_manager_.decide_when_to_send_acks()) { + has_pending_ack = received_packet_manager_.ack_timeout().IsInitialized(); + } else { + has_pending_ack = ack_alarm_->IsSet(); + } + if (!has_pending_ack && stop_waiting_count_ <= 1) { // No need to send an ACK. return frames; } @@ -2597,7 +2623,11 @@ } void QuicConnection::SendAck() { - ResetAckStates(); + if (!received_packet_manager_.decide_when_to_send_acks()) { + // When received_packet_manager decides when to send ack, delaying + // ResetAckStates until ACK is successfully flushed. + ResetAckStates(); + } if (packet_generator_.deprecate_ack_bundling_mode()) { QUIC_DVLOG(1) << ENDPOINT << "Sending an ACK proactively"; @@ -2608,7 +2638,14 @@ PopulateStopWaitingFrame(&stop_waiting); frames.push_back(QuicFrame(stop_waiting)); } - send_ack_when_on_can_write_ = !packet_generator_.FlushAckFrame(frames); + if (received_packet_manager_.decide_when_to_send_acks()) { + if (!packet_generator_.FlushAckFrame(frames)) { + return; + } + ResetAckStates(); + } else { + send_ack_when_on_can_write_ = !packet_generator_.FlushAckFrame(frames); + } } else { packet_generator_.SetShouldSendAck(!no_stop_waiting_frames_); } @@ -3139,21 +3176,39 @@ } if (flush_and_set_pending_retransmission_alarm_on_delete_) { - if (connection_->packet_generator_.deprecate_ack_bundling_mode() && - connection_->ack_alarm_->IsSet() && - connection_->ack_alarm_->deadline() <= - connection_->clock_->ApproximateNow()) { - // An ACK needs to be sent right now. This ACK did not get bundled - // because either there was no data to write or packets were marked as - // received after frames were queued in the generator. - if (connection_->send_alarm_->IsSet() && - connection_->send_alarm_->deadline() <= + if (connection_->packet_generator_.deprecate_ack_bundling_mode()) { + if (connection_->received_packet_manager_.decide_when_to_send_acks()) { + const QuicTime ack_timeout = + connection_->received_packet_manager_.ack_timeout(); + if (ack_timeout.IsInitialized()) { + if (ack_timeout <= connection_->clock_->ApproximateNow() && + !connection_->CanWrite(NO_RETRANSMITTABLE_DATA)) { + // Cancel ACK alarm if connection is write blocked, and ACK will be + // sent when connection gets unblocked. + connection_->ack_alarm_->Cancel(); + } else { + connection_->MaybeSetAckAlarmTo(ack_timeout); + } + } + } + if (connection_->ack_alarm_->IsSet() && + connection_->ack_alarm_->deadline() <= connection_->clock_->ApproximateNow()) { - // If send alarm will go off soon, let send alarm send the ACK. - connection_->ack_alarm_->Cancel(); - connection_->send_ack_when_on_can_write_ = true; - } else { - connection_->SendAck(); + // An ACK needs to be sent right now. This ACK did not get bundled + // because either there was no data to write or packets were marked as + // received after frames were queued in the generator. + if (connection_->send_alarm_->IsSet() && + connection_->send_alarm_->deadline() <= + connection_->clock_->ApproximateNow()) { + // If send alarm will go off soon, let send alarm send the ACK. + connection_->ack_alarm_->Cancel(); + if (!connection_->received_packet_manager_ + .decide_when_to_send_acks()) { + connection_->send_ack_when_on_can_write_ = true; + } + } else { + connection_->SendAck(); + } } } connection_->packet_generator_.Flush(); @@ -3659,6 +3714,9 @@ stop_waiting_count_ = 0; num_retransmittable_packets_received_since_last_ack_sent_ = 0; num_packets_received_since_last_ack_sent_ = 0; + if (received_packet_manager_.decide_when_to_send_acks()) { + received_packet_manager_.ResetAckStates(); + } } MessageStatus QuicConnection::SendMessage(QuicMessageId message_id, @@ -3722,5 +3780,36 @@ return ENCRYPTION_NONE; } +size_t QuicConnection::min_received_before_ack_decimation() const { + if (received_packet_manager_.decide_when_to_send_acks()) { + return received_packet_manager_.min_received_before_ack_decimation(); + } + return min_received_before_ack_decimation_; +} + +void QuicConnection::set_min_received_before_ack_decimation(size_t new_value) { + if (received_packet_manager_.decide_when_to_send_acks()) { + received_packet_manager_.set_min_received_before_ack_decimation(new_value); + } else { + min_received_before_ack_decimation_ = new_value; + } +} + +size_t QuicConnection::ack_frequency_before_ack_decimation() const { + if (received_packet_manager_.decide_when_to_send_acks()) { + return received_packet_manager_.ack_frequency_before_ack_decimation(); + } + return ack_frequency_before_ack_decimation_; +} + +void QuicConnection::set_ack_frequency_before_ack_decimation(size_t new_value) { + DCHECK_GT(new_value, 0u); + if (received_packet_manager_.decide_when_to_send_acks()) { + received_packet_manager_.set_ack_frequency_before_ack_decimation(new_value); + } else { + ack_frequency_before_ack_decimation_ = new_value; + } +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h index 6b730a91..667fac97 100644 --- a/net/third_party/quic/core/quic_connection.h +++ b/net/third_party/quic/core/quic_connection.h
@@ -336,8 +336,6 @@ NO_ACK, }; - enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING }; - // Constructs a new QuicConnection for |connection_id| and // |initial_peer_address| using |writer| to write packets. |owns_writer| // specifies whether the connection takes ownership of |writer|. |helper| must @@ -380,9 +378,6 @@ // Returns the max pacing rate for the connection. virtual QuicBandwidth MaxPacingRate() const; - // Sets the number of active streams on the connection for congestion control. - void SetNumOpenStreams(size_t num_streams); - // Sends crypto handshake messages of length |write_length| to the peer in as // few packets as possible. Returns the number of bytes consumed from the // data. @@ -820,20 +815,11 @@ return packet_generator_.fully_pad_crypto_handshake_packets(); } - size_t min_received_before_ack_decimation() const { - return min_received_before_ack_decimation_; - } - void set_min_received_before_ack_decimation(size_t new_value) { - min_received_before_ack_decimation_ = new_value; - } + size_t min_received_before_ack_decimation() const; + void set_min_received_before_ack_decimation(size_t new_value); - size_t ack_frequency_before_ack_decimation() const { - return ack_frequency_before_ack_decimation_; - } - void set_ack_frequency_before_ack_decimation(size_t new_value) { - DCHECK_GT(new_value, 0u); - ack_frequency_before_ack_decimation_ = new_value; - } + size_t ack_frequency_before_ack_decimation() const; + void set_ack_frequency_before_ack_decimation(size_t new_value); // 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 @@ -1172,6 +1158,8 @@ QuicPacketHeader last_header_; bool should_last_packet_instigate_acks_; // Whether the most recent packet was missing before it was received. + // TODO(fayang): Remove was_last_packet_missing_ when deprecating + // quic_rpm_decides_when_to_send_acks. bool was_last_packet_missing_; // Track some peer state so we can do less bookkeeping @@ -1234,12 +1222,18 @@ // quic_deprecate_ack_bundling_mode. bool ack_queued_; // How many retransmittable packets have arrived without sending an ack. + // TODO(fayang): Remove + // num_retransmittable_packets_received_since_last_ack_sent_ when deprecating + // quic_rpm_decides_when_to_send_acks. QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_; // 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_; + // TODO(fayang): Remove ack_mode_, ack_decimation_delay_, + // unlimited_ack_decimation_, fast_ack_after_quiescence_ when deprecating + // quic_rpm_decides_when_to_send_acks. // Indicates the current ack mode, defaults to acking every 2 packets. AckMode ack_mode_; // The max delay in fraction of min_rtt to use when sending decimated acks. @@ -1311,6 +1305,8 @@ QuicTime time_of_last_received_packet_; // The time the previous ack-instigating packet was received and processed. + // TODO(fayang): Remove time_of_previous_received_packet_ when deprecating + // quic_rpm_decides_when_to_send_acks. QuicTime time_of_previous_received_packet_; // Sent packet manager which tracks the status of packets sent by this @@ -1394,9 +1390,13 @@ size_t max_consecutive_num_packets_with_no_retransmittable_frames_; // Ack decimation will start happening after this many packets are received. + // TODO(fayang): Remove min_received_before_ack_decimation_ when deprecating + // quic_rpm_decides_when_to_send_acks. size_t min_received_before_ack_decimation_; // Before ack decimation starts (if enabled), we ack every n-th packet. + // TODO(fayang): Remove ack_frequency_before_ack_decimation_ when deprecating + // quic_rpm_decides_when_to_send_acks. size_t ack_frequency_before_ack_decimation_; // If true, the connection will fill up the pipe with extra data whenever the
diff --git a/net/third_party/quic/core/quic_connection_test.cc b/net/third_party/quic/core/quic_connection_test.cc index 1203b71..a47f992 100644 --- a/net/third_party/quic/core/quic_connection_test.cc +++ b/net/third_party/quic/core/quic_connection_test.cc
@@ -830,14 +830,16 @@ : connection_id_(TestConnectionId()), framer_(SupportedVersions(version()), QuicTime::Zero(), - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + connection_id_.length()), send_algorithm_(new StrictMock<MockSendAlgorithm>), loss_algorithm_(new MockLossAlgorithm()), helper_(new TestConnectionHelper(&clock_, &random_generator_)), alarm_factory_(new TestAlarmFactory()), peer_framer_(SupportedVersions(version()), QuicTime::Zero(), - Perspective::IS_SERVER), + Perspective::IS_SERVER, + connection_id_.length()), peer_creator_(connection_id_, &peer_framer_, /*delegate=*/nullptr), @@ -2346,8 +2348,7 @@ QuicTime::Delta::Zero(), QuicTime::Zero()); EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode( - &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); // Start ack decimation from 10th packet. connection_.set_min_received_before_ack_decimation(10); @@ -5155,7 +5156,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); const size_t kMinRttMs = 40; RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); @@ -5213,7 +5214,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true); const size_t kMinRttMs = 40; @@ -5399,7 +5400,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); const size_t kMinRttMs = 40; @@ -5458,8 +5459,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode( - &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); const size_t kMinRttMs = 40; RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); @@ -5523,8 +5523,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode( - &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); const size_t kMinRttMs = 40; RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); @@ -5607,8 +5606,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode( - &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); const size_t kMinRttMs = 40; @@ -5676,8 +5674,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReorderingEighthRtt) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode( - &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); const size_t kMinRttMs = 40;
diff --git a/net/third_party/quic/core/quic_constants.h b/net/third_party/quic/core/quic_constants.h index f17b6d2..571af03 100644 --- a/net/third_party/quic/core/quic_constants.h +++ b/net/third_party/quic/core/quic_constants.h
@@ -214,10 +214,6 @@ // Number of bytes reserved for connection ID length. const size_t kConnectionIdLengthSize = 1; -// Length of an encoded variable length connection ID, in bytes. -// TODO(dschinazi) b/120240679 - remove kQuicConnectionIdLength -const size_t kQuicConnectionIdLength = 8; - // Minimum length of random bytes in IETF stateless reset packet. const size_t kMinRandomBytesLengthInStatelessReset = 24;
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc index 536aac74..32e56d3 100644 --- a/net/third_party/quic/core/quic_dispatcher.cc +++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -277,7 +277,8 @@ QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, - std::unique_ptr<QuicAlarmFactory> alarm_factory) + std::unique_ptr<QuicAlarmFactory> alarm_factory, + uint8_t expected_connection_id_length) : config_(config), crypto_config_(crypto_config), compressed_certs_cache_( @@ -292,7 +293,8 @@ version_manager_(version_manager), framer_(GetSupportedVersions(), /*unused*/ QuicTime::Zero(), - Perspective::IS_SERVER), + Perspective::IS_SERVER, + expected_connection_id_length), last_error_(QUIC_NO_ERROR), new_sessions_allowed_per_event_loop_(0u), accept_new_connections_(true) { @@ -1173,7 +1175,7 @@ if (FLAGS_quic_allow_chlo_buffering && !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), config_->create_session_tag_indicators(), - &alpn_extractor)) { + &alpn_extractor, connection_id.length())) { // Buffer non-CHLO packets. ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version); @@ -1195,7 +1197,7 @@ rejector.get()); if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), config_->create_session_tag_indicators(), - &validator)) { + &validator, connection_id.length())) { ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version); return; }
diff --git a/net/third_party/quic/core/quic_dispatcher.h b/net/third_party/quic/core/quic_dispatcher.h index 99d3025..2f7e78c 100644 --- a/net/third_party/quic/core/quic_dispatcher.h +++ b/net/third_party/quic/core/quic_dispatcher.h
@@ -49,7 +49,8 @@ QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, - std::unique_ptr<QuicAlarmFactory> alarm_factory); + std::unique_ptr<QuicAlarmFactory> alarm_factory, + uint8_t expected_connection_id_length); QuicDispatcher(const QuicDispatcher&) = delete; QuicDispatcher& operator=(const QuicDispatcher&) = delete;
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc index 2c2343b..fa8b4a5 100644 --- a/net/third_party/quic/core/quic_dispatcher_test.cc +++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -125,7 +125,8 @@ std::unique_ptr<QuicCryptoServerStream::Helper>( new QuicSimpleCryptoServerStreamHelper( QuicRandom::GetInstance())), - QuicMakeUnique<MockAlarmFactory>()) {} + QuicMakeUnique<MockAlarmFactory>(), + kQuicDefaultConnectionIdLength) {} MOCK_METHOD4(CreateQuicSession, QuicServerSessionBase*(QuicConnectionId connection_id, @@ -292,7 +293,8 @@ std::unique_ptr<QuicReceivedPacket> received_packet( ConstructReceivedPacket(*packet, mock_helper_.GetClock()->Now())); - if (ChloExtractor::Extract(*packet, versions, {}, nullptr)) { + if (ChloExtractor::Extract(*packet, versions, {}, nullptr, + connection_id.length())) { // Add CHLO packet to the beginning to be verified first, because it is // also processed first by new session. data_connection_map_[connection_id].push_front(
diff --git a/net/third_party/quic/core/quic_epoll_alarm_factory.cc b/net/third_party/quic/core/quic_epoll_alarm_factory.cc index 3f6f3df3..bd4b6b2 100644 --- a/net/third_party/quic/core/quic_epoll_alarm_factory.cc +++ b/net/third_party/quic/core/quic_epoll_alarm_factory.cc
@@ -4,6 +4,8 @@ #include "net/third_party/quic/core/quic_epoll_alarm_factory.h" +#include <type_traits> + #include "net/third_party/quic/core/quic_arena_scoped_ptr.h" namespace quic { @@ -42,10 +44,12 @@ private: class EpollAlarmImpl : public QuicEpollAlarmBase { public: + using int64_epoll = decltype(QuicEpollAlarmBase().OnAlarm()); + explicit EpollAlarmImpl(QuicEpollAlarm* alarm) : alarm_(alarm) {} // Use the same integer type as the base class. - int64_t /* allow-non-std-int */ OnAlarm() override { + int64_epoll OnAlarm() override { QuicEpollAlarmBase::OnAlarm(); alarm_->Fire(); // Fire will take care of registering the alarm, if needed. @@ -78,8 +82,8 @@ if (arena != nullptr) { return arena->New<QuicEpollAlarm>(epoll_server_, std::move(delegate)); } - return QuicArenaScopedPtr<QuicAlarm>( - new QuicEpollAlarm(epoll_server_, std::move(delegate))); + return QuicArenaScopedPtr<QuicAlarm>( + new QuicEpollAlarm(epoll_server_, std::move(delegate))); } } // namespace quic
diff --git a/net/third_party/quic/core/quic_epoll_connection_helper.h b/net/third_party/quic/core/quic_epoll_connection_helper.h index 95d5545..739b570 100644 --- a/net/third_party/quic/core/quic_epoll_connection_helper.h +++ b/net/third_party/quic/core/quic_epoll_connection_helper.h
@@ -17,6 +17,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quic/core/quic_time.h" +#include "net/third_party/quic/platform/api/quic_default_buffer_allocator.h" #include "net/third_party/quic/platform/api/quic_epoll.h" #include "net/third_party/quic/platform/impl/quic_epoll_clock.h" @@ -24,8 +25,6 @@ class QuicRandom; -using QuicStreamBufferAllocator = SimpleBufferAllocator; - enum class QuicAllocator { SIMPLE, BUFFER_POOL }; class QuicEpollConnectionHelper : public QuicConnectionHelperInterface { @@ -46,7 +45,7 @@ QuicRandom* random_generator_; // Set up allocators. They take up minimal memory before use. // Allocator for stream send buffers. - QuicStreamBufferAllocator stream_buffer_allocator_; + QuicDefaultBufferAllocator stream_buffer_allocator_; SimpleBufferAllocator simple_buffer_allocator_; QuicAllocator allocator_type_; };
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc index d4b93ab..4b877b7e 100644 --- a/net/third_party/quic/core/quic_framer.cc +++ b/net/third_party/quic/core/quic_framer.cc
@@ -17,6 +17,7 @@ #include "net/third_party/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quic/core/crypto/quic_random.h" #include "net/third_party/quic/core/quic_connection_id.h" +#include "net/third_party/quic/core/quic_constants.h" #include "net/third_party/quic/core/quic_data_reader.h" #include "net/third_party/quic/core/quic_data_writer.h" #include "net/third_party/quic/core/quic_socket_address_coder.h" @@ -452,7 +453,8 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, - Perspective perspective) + Perspective perspective, + uint8_t expected_connection_id_length) : visitor_(nullptr), error_(QUIC_NO_ERROR), last_serialized_connection_id_(EmptyQuicConnectionId()), @@ -470,7 +472,8 @@ first_sending_packet_number_(FirstSendingPacketNumber()), data_producer_(nullptr), infer_packet_header_type_from_version_(perspective == - Perspective::IS_CLIENT) { + Perspective::IS_CLIENT), + expected_connection_id_length_(expected_connection_id_length) { DCHECK(!supported_versions.empty()); version_ = supported_versions_[0]; decrypter_ = QuicMakeUnique<NullDecrypter>(perspective); @@ -764,7 +767,7 @@ const QuicNewConnectionIdFrame& frame) { return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.sequence_number) + - kConnectionIdLengthSize + kQuicConnectionIdLength + + kConnectionIdLengthSize + frame.connection_id.length() + sizeof(frame.stateless_reset_token); } @@ -2543,11 +2546,11 @@ uint8_t destination_connection_id_length = header->destination_connection_id_included == CONNECTION_ID_PRESENT - ? kQuicDefaultConnectionIdLength + ? expected_connection_id_length_ : 0; uint8_t source_connection_id_length = header->source_connection_id_included == CONNECTION_ID_PRESENT - ? kQuicDefaultConnectionIdLength + ? expected_connection_id_length_ : 0; if (header->form == IETF_QUIC_LONG_HEADER_PACKET) { // Read and validate connection ID length. @@ -2567,9 +2570,6 @@ } if (dcil != destination_connection_id_length || scil != source_connection_id_length) { - // Long header packets received by client must include 8-byte source - // connection ID, and those received by server must include 8-byte - // destination connection ID. QUIC_DVLOG(1) << "dcil: " << static_cast<uint32_t>(dcil) << ", scil: " << static_cast<uint32_t>(scil); set_detailed_error("Invalid ConnectionId length."); @@ -3666,10 +3666,7 @@ set_detailed_error("Unable to read least unacked delta."); return false; } - if (header.packet_number.ToUint64() < least_unacked_delta || - (GetQuicReloadableFlag( - quic_close_connection_with_zero_least_unacked_stop_waiting) && - header.packet_number.ToUint64() == least_unacked_delta)) { + if (header.packet_number.ToUint64() <= least_unacked_delta) { set_detailed_error("Invalid unacked delta."); return false; } @@ -5566,7 +5563,7 @@ set_detailed_error("Can not write New Connection ID sequence number"); return false; } - if (!writer->WriteUInt8(kQuicConnectionIdLength)) { + if (!writer->WriteUInt8(frame.connection_id.length())) { set_detailed_error( "Can not write New Connection ID frame connection ID Length"); return false; @@ -5600,8 +5597,7 @@ return false; } - // TODO(dschinazi) b/120240679 - remove this check - if (connection_id_length != kQuicConnectionIdLength) { + if (connection_id_length != kQuicDefaultConnectionIdLength) { set_detailed_error("Invalid new connection ID length."); return false; }
diff --git a/net/third_party/quic/core/quic_framer.h b/net/third_party/quic/core/quic_framer.h index 8d45a4a0..ac1efa4 100644 --- a/net/third_party/quic/core/quic_framer.h +++ b/net/third_party/quic/core/quic_framer.h
@@ -224,7 +224,8 @@ // version in |supported_versions|. QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, - Perspective perspective); + Perspective perspective, + uint8_t expected_connection_id_length); QuicFramer(const QuicFramer&) = delete; QuicFramer& operator=(const QuicFramer&) = delete; @@ -915,6 +916,12 @@ // Otherwise, framer infers packet header type from first byte of a received // packet. bool infer_packet_header_type_from_version_; + + // IETF short headers contain a destination connection ID but do not + // encode its length. This variable contains the length we expect to read. + // This is also used to validate the long header connection ID lengths in + // older versions of QUIC. + const uint8_t expected_connection_id_length_; }; } // namespace quic
diff --git a/net/third_party/quic/core/quic_framer_test.cc b/net/third_party/quic/core/quic_framer_test.cc index dc283ee8..cdf565c5 100644 --- a/net/third_party/quic/core/quic_framer_test.cc +++ b/net/third_party/quic/core/quic_framer_test.cc
@@ -14,6 +14,7 @@ #include "net/third_party/quic/core/crypto/null_encrypter.h" #include "net/third_party/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quic/core/quic_connection_id.h" #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/core/quic_utils.h" @@ -434,7 +435,8 @@ start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), framer_(AllSupportedVersionsIncludingTls(), start_, - Perspective::IS_SERVER) { + Perspective::IS_SERVER, + kQuicDefaultConnectionIdLength) { SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); framer_.set_version(version_); framer_.SetDecrypter(ENCRYPTION_NONE, @@ -9695,7 +9697,7 @@ size_t size, const ParsedQuicVersion& version) { QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), - Perspective::IS_SERVER); + Perspective::IS_SERVER, kQuicDefaultConnectionIdLength); ASSERT_EQ(GetQuicFlag(FLAGS_quic_supports_tls_handshake), true); const char* const packet_bytes = reinterpret_cast<const char*>(data); @@ -12882,6 +12884,46 @@ ASSERT_EQ(visitor_.coalesced_packets_.size(), 0u); } +TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { + if (framer_.transport_version() < QUIC_VERSION_46) { + return; + } + char connection_id_bytes[9] = {0xFE, 0xDC, 0xBA, 0x98, 0x76, + 0x54, 0x32, 0x10, 0x42}; + QuicConnectionId connection_id(connection_id_bytes, + sizeof(connection_id_bytes)); + QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); + QuicFramerPeer::SetExpectedConnectionIDLength(&framer_, + connection_id.length()); + + // clang-format off + PacketFragments packet = { + // type (8 byte connection_id and 1 byte packet number) + {"Unable to read type.", + {0x40}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, + // packet number + {"Unable to read packet number.", + {0x78}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet)); + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_EQ(connection_id, visitor_.header_->destination_connection_id); + EXPECT_FALSE(visitor_.header_->reset_flag); + EXPECT_FALSE(visitor_.header_->version_flag); + EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); + EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); + + CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); +} + } // namespace } // namespace test } // namespace quic
diff --git a/net/third_party/quic/core/quic_ietf_framer_test.cc b/net/third_party/quic/core/quic_ietf_framer_test.cc index 802dc71..7111c86e 100644 --- a/net/third_party/quic/core/quic_ietf_framer_test.cc +++ b/net/third_party/quic/core/quic_ietf_framer_test.cc
@@ -210,7 +210,10 @@ public: QuicIetfFramerTest() : start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), - framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER) { + framer_(AllSupportedVersions(), + start_, + Perspective::IS_SERVER, + kQuicDefaultConnectionIdLength) { framer_.set_visitor(&visitor_); }
diff --git a/net/third_party/quic/core/quic_packet_creator_test.cc b/net/third_party/quic/core/quic_packet_creator_test.cc index 1ec5056..de214f0 100644 --- a/net/third_party/quic/core/quic_packet_creator_test.cc +++ b/net/third_party/quic/core/quic_packet_creator_test.cc
@@ -135,13 +135,15 @@ protected: QuicPacketCreatorTest() - : server_framer_(SupportedVersions(GetParam().version), + : connection_id_(TestConnectionId(2)), + server_framer_(SupportedVersions(GetParam().version), QuicTime::Zero(), - Perspective::IS_SERVER), + Perspective::IS_SERVER, + connection_id_.length()), client_framer_(SupportedVersions(GetParam().version), QuicTime::Zero(), - Perspective::IS_CLIENT), - connection_id_(TestConnectionId(2)), + Perspective::IS_CLIENT, + connection_id_.length()), data_("foo"), creator_(connection_id_, &client_framer_, &delegate_, &producer_), serialized_packet_(creator_.NoPacket()) { @@ -245,12 +247,12 @@ static const QuicStreamOffset kOffset = 0u; char buffer_[kMaxPacketSize]; + QuicConnectionId connection_id_; QuicFrames frames_; QuicFramer server_framer_; QuicFramer client_framer_; StrictMock<MockFramerVisitor> framer_visitor_; StrictMock<MockPacketCreatorDelegate> delegate_; - QuicConnectionId connection_id_; QuicString data_; struct iovec iov_; TestPacketCreator creator_;
diff --git a/net/third_party/quic/core/quic_packet_generator_test.cc b/net/third_party/quic/core/quic_packet_generator_test.cc index c99d0b4..dc4cac7 100644 --- a/net/third_party/quic/core/quic_packet_generator_test.cc +++ b/net/third_party/quic/core/quic_packet_generator_test.cc
@@ -201,7 +201,8 @@ QuicPacketGeneratorTest() : framer_(AllSupportedVersions(), QuicTime::Zero(), - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + kQuicDefaultConnectionIdLength), generator_(TestConnectionId(), &framer_, &random_generator_,
diff --git a/net/third_party/quic/core/quic_packet_reader.cc b/net/third_party/quic/core/quic_packet_reader.cc index 6dbe6d2..129f6dd 100644 --- a/net/third_party/quic/core/quic_packet_reader.cc +++ b/net/third_party/quic/core/quic_packet_reader.cc
@@ -65,7 +65,7 @@ const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped) { -#if MMSG_MORE +#if MMSG_MORE_NO_ANDROID return ReadAndDispatchManyPackets(fd, port, clock, processor, packets_dropped); #else @@ -80,7 +80,7 @@ const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped) { -#if MMSG_MORE +#if MMSG_MORE_NO_ANDROID // Re-set the length fields in case recvmmsg has changed them. for (int i = 0; i < kNumPacketsPerReadMmsgCall; ++i) { DCHECK_LE(kMaxPacketSize, packets_[i].iov.iov_len);
diff --git a/net/third_party/quic/core/quic_packet_reader.h b/net/third_party/quic/core/quic_packet_reader.h index 577e63e..5b018aa 100644 --- a/net/third_party/quic/core/quic_packet_reader.h +++ b/net/third_party/quic/core/quic_packet_reader.h
@@ -19,8 +19,6 @@ #include "net/third_party/quic/platform/api/quic_socket_address.h" #include "net/third_party/quic/platform/impl/quic_socket_utils.h" -#define MMSG_MORE 0 - namespace quic { #if MMSG_MORE
diff --git a/net/third_party/quic/core/quic_received_packet_manager.cc b/net/third_party/quic/core/quic_received_packet_manager.cc index 8bf9a65..5d63eef6 100644 --- a/net/third_party/quic/core/quic_received_packet_manager.cc +++ b/net/third_party/quic/core/quic_received_packet_manager.cc
@@ -8,6 +8,7 @@ #include <limits> #include <utility> +#include "net/third_party/quic/core/congestion_control/rtt_stats.h" #include "net/third_party/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quic/core/quic_connection_stats.h" #include "net/third_party/quic/platform/api/quic_bug_tracker.h" @@ -23,6 +24,19 @@ // Set to the number of nacks needed for fast retransmit plus one for protection // against an ack loss const size_t kMaxPacketsAfterNewMissing = 4; + +// Maximum number of retransmittable packets received before sending an ack. +const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2; +// Minimum number of packets received before ack decimation is enabled. +// This intends to avoid the beginning of slow start, when CWNDs may be +// rapidly increasing. +const QuicPacketCount kMinReceivedBeforeAckDecimation = 100; +// Wait for up to 10 retransmittable packets before sending an ack. +const QuicPacketCount kMaxRetransmittablePacketsBeforeAck = 10; +// One quarter RTT delay when doing ack decimation. +const float kAckDecimationDelay = 0.25; +// One eighth RTT delay when doing ack decimation. +const float kShortAckDecimationDelay = 0.125; } // namespace QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats) @@ -30,15 +44,63 @@ max_ack_ranges_(0), time_largest_observed_(QuicTime::Zero()), save_timestamps_(false), - stats_(stats) {} + stats_(stats), + ack_mode_(GetQuicReloadableFlag(quic_enable_ack_decimation) + ? ACK_DECIMATION + : TCP_ACKING), + num_retransmittable_packets_received_since_last_ack_sent_(0), + min_received_before_ack_decimation_(kMinReceivedBeforeAckDecimation), + ack_frequency_before_ack_decimation_( + kDefaultRetransmittablePacketsBeforeAck), + ack_decimation_delay_(kAckDecimationDelay), + unlimited_ack_decimation_(false), + fast_ack_after_quiescence_(false), + ack_timeout_(QuicTime::Zero()), + time_of_previous_received_packet_(QuicTime::Zero()), + was_last_packet_missing_(false), + decide_when_to_send_acks_( + GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode) && + GetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks)) {} QuicReceivedPacketManager::~QuicReceivedPacketManager() {} +void QuicReceivedPacketManager::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + DCHECK(decide_when_to_send_acks_); + if (GetQuicReloadableFlag(quic_enable_ack_decimation) && + config.HasClientSentConnectionOption(kACD0, perspective)) { + ack_mode_ = TCP_ACKING; + } + if (config.HasClientSentConnectionOption(kACKD, perspective)) { + ack_mode_ = ACK_DECIMATION; + } + if (config.HasClientSentConnectionOption(kAKD2, perspective)) { + ack_mode_ = ACK_DECIMATION_WITH_REORDERING; + } + if (config.HasClientSentConnectionOption(kAKD3, perspective)) { + ack_mode_ = ACK_DECIMATION; + ack_decimation_delay_ = kShortAckDecimationDelay; + } + if (config.HasClientSentConnectionOption(kAKD4, perspective)) { + ack_mode_ = ACK_DECIMATION_WITH_REORDERING; + ack_decimation_delay_ = kShortAckDecimationDelay; + } + if (config.HasClientSentConnectionOption(kAKDU, perspective)) { + unlimited_ack_decimation_ = true; + } + if (config.HasClientSentConnectionOption(kACKQ, perspective)) { + fast_ack_after_quiescence_ = true; + } +} + void QuicReceivedPacketManager::RecordPacketReceived( const QuicPacketHeader& header, QuicTime receipt_time) { const QuicPacketNumber packet_number = header.packet_number; DCHECK(IsAwaitingPacket(packet_number)) << " packet_number:" << packet_number; + if (decide_when_to_send_acks_) { + was_last_packet_missing_ = IsMissing(packet_number); + } if (!ack_frame_updated_) { ack_frame_.received_packet_times.clear(); } @@ -99,7 +161,9 @@ const QuicFrame QuicReceivedPacketManager::GetUpdatedAckFrame( QuicTime approximate_now) { - ack_frame_updated_ = false; + if (!decide_when_to_send_acks_) { + ack_frame_updated_ = false; + } if (time_largest_observed_ == QuicTime::Zero()) { // We have received no packets. ack_frame_.ack_delay_time = QuicTime::Delta::Infinite(); @@ -151,6 +215,102 @@ ack_frame_.packets.Min() >= peer_least_packet_awaiting_ack_); } +void QuicReceivedPacketManager::MaybeUpdateAckTimeout( + bool should_last_packet_instigate_acks, + QuicPacketNumber last_received_packet_number, + QuicTime time_of_last_received_packet, + QuicTime now, + const RttStats* rtt_stats, + QuicTime::Delta delayed_ack_time) { + DCHECK(decide_when_to_send_acks_); + if (!ack_frame_updated_) { + // ACK frame has not been updated, nothing to do. + return; + } + + if (was_last_packet_missing_ && last_sent_largest_acked_.IsInitialized() && + last_received_packet_number < last_sent_largest_acked_) { + // Only ack immediately if an ACK frame was sent with a larger largest acked + // than the newly received packet number. + ack_timeout_ = now; + return; + } + + if (!should_last_packet_instigate_acks) { + return; + } + + ++num_retransmittable_packets_received_since_last_ack_sent_; + if (ack_mode_ != TCP_ACKING && + last_received_packet_number >= PeerFirstSendingPacketNumber() + + min_received_before_ack_decimation_) { + // Ack up to 10 packets at once unless ack decimation is unlimited. + if (!unlimited_ack_decimation_ && + num_retransmittable_packets_received_since_last_ack_sent_ >= + kMaxRetransmittablePacketsBeforeAck) { + ack_timeout_ = now; + return; + } + // Wait for the minimum of the ack decimation delay or the delayed ack time + // before sending an ack. + QuicTime::Delta ack_delay = std::min( + delayed_ack_time, rtt_stats->min_rtt() * ack_decimation_delay_); + if (fast_ack_after_quiescence_ && now - time_of_previous_received_packet_ > + rtt_stats->SmoothedOrInitialRtt()) { + // Ack the first packet out of queiscence faster, because QUIC does + // not pace the first few packets and commonly these may be handshake + // or TLP packets, which we'd like to acknowledge quickly. + ack_delay = QuicTime::Delta::FromMilliseconds(1); + } + MaybeUpdateAckTimeoutTo(now + ack_delay); + } else { + // Ack with a timer or every 2 packets by default. + if (num_retransmittable_packets_received_since_last_ack_sent_ >= + ack_frequency_before_ack_decimation_) { + ack_timeout_ = now; + } else if (fast_ack_after_quiescence_ && + (now - time_of_previous_received_packet_) > + rtt_stats->SmoothedOrInitialRtt()) { + // Ack the first packet out of queiscence faster, because QUIC does + // not pace the first few packets and commonly these may be handshake + // or TLP packets, which we'd like to acknowledge quickly. + MaybeUpdateAckTimeoutTo(now + QuicTime::Delta::FromMilliseconds(1)); + } else { + MaybeUpdateAckTimeoutTo(now + delayed_ack_time); + } + } + + // If there are new missing packets to report, send an ack immediately. + if (HasNewMissingPackets()) { + if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) { + // Wait the minimum of an eighth min_rtt and the existing ack time. + QuicTime ack_time = now + kShortAckDecimationDelay * rtt_stats->min_rtt(); + MaybeUpdateAckTimeoutTo(ack_time); + } else { + ack_timeout_ = now; + } + } + + if (fast_ack_after_quiescence_) { + time_of_previous_received_packet_ = time_of_last_received_packet; + } +} + +void QuicReceivedPacketManager::ResetAckStates() { + DCHECK(decide_when_to_send_acks_); + ack_frame_updated_ = false; + ack_timeout_ = QuicTime::Zero(); + num_retransmittable_packets_received_since_last_ack_sent_ = 0; + last_sent_largest_acked_ = LargestAcked(ack_frame_); +} + +void QuicReceivedPacketManager::MaybeUpdateAckTimeoutTo(QuicTime time) { + DCHECK(decide_when_to_send_acks_); + if (!ack_timeout_.IsInitialized() || ack_timeout_ > time) { + ack_timeout_ = time; + } +} + bool QuicReceivedPacketManager::HasMissingPackets() const { if (ack_frame_.packets.Empty()) { return false;
diff --git a/net/third_party/quic/core/quic_received_packet_manager.h b/net/third_party/quic/core/quic_received_packet_manager.h index f438702..099d6ca 100644 --- a/net/third_party/quic/core/quic_received_packet_manager.h +++ b/net/third_party/quic/core/quic_received_packet_manager.h
@@ -13,8 +13,11 @@ namespace quic { +class RttStats; + namespace test { class QuicConnectionPeer; +class QuicReceivedPacketManagerPeer; } // namespace test struct QuicConnectionStats; @@ -28,6 +31,8 @@ delete; virtual ~QuicReceivedPacketManager(); + void SetFromConfig(const QuicConfig& config, Perspective perspective); + // Updates the internal state concerning which packets have been received. // header: the packet header. // timestamp: the arrival time of the packet. @@ -50,6 +55,20 @@ // received after this call. void DontWaitForPacketsBefore(QuicPacketNumber least_unacked); + // Called to update ack_timeout_ to the time when an ACK needs to be sent. A + // caller can decide whether and when to send an ACK by retrieving + // ack_timeout_. If ack_timeout_ is not initialized, no ACK needs to be sent. + // Otherwise, ACK needs to be sent by the specified time. + void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, + QuicPacketNumber last_received_packet_number, + QuicTime time_of_last_received_packet, + QuicTime now, + const RttStats* rtt_stats, + QuicTime::Delta delayed_ack_time); + + // Resets ACK related states, called after an ACK is successfully sent. + void ResetAckStates(); + // Returns true if there are any missing packets. bool HasMissingPackets() const; @@ -83,8 +102,31 @@ save_timestamps_ = save_timestamps; } + size_t min_received_before_ack_decimation() const { + return min_received_before_ack_decimation_; + } + void set_min_received_before_ack_decimation(size_t new_value) { + min_received_before_ack_decimation_ = new_value; + } + + size_t ack_frequency_before_ack_decimation() const { + return ack_frequency_before_ack_decimation_; + } + void set_ack_frequency_before_ack_decimation(size_t new_value) { + DCHECK_GT(new_value, 0u); + ack_frequency_before_ack_decimation_ = new_value; + } + + QuicTime ack_timeout() const { return ack_timeout_; } + + bool decide_when_to_send_acks() const { return decide_when_to_send_acks_; } + private: friend class test::QuicConnectionPeer; + friend class test::QuicReceivedPacketManagerPeer; + + // Sets ack_timeout_ to |time| if ack_timeout_ is not initialized or > time. + void MaybeUpdateAckTimeoutTo(QuicTime time); // Least packet number of the the packet sent by the peer for which it // hasn't received an ack. @@ -112,6 +154,38 @@ QuicPacketNumber least_received_packet_number_; QuicConnectionStats* stats_; + + AckMode ack_mode_; + // How many retransmittable packets have arrived without sending an ack. + QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_; + // Ack decimation will start happening after this many packets are received. + size_t min_received_before_ack_decimation_; + // Before ack decimation starts (if enabled), we ack every n-th packet. + size_t ack_frequency_before_ack_decimation_; + // The max delay in fraction of min_rtt to use when sending decimated acks. + float ack_decimation_delay_; + // When true, removes ack decimation's max number of packets(10) before + // sending an ack. + bool unlimited_ack_decimation_; + // When true, use a 1ms delayed ack timer if it's been an SRTT since a packet + // was received. + bool fast_ack_after_quiescence_; + + // Time that an ACK needs to be sent. 0 means no ACK is pending. Used when + // decide_when_to_send_acks_ is true. + QuicTime ack_timeout_; + + // The time the previous ack-instigating packet was received and processed. + QuicTime time_of_previous_received_packet_; + // Whether the most recent packet was missing before it was received. + bool was_last_packet_missing_; + + // Last sent largest acked, which gets updated when ACK was successfully sent. + QuicPacketNumber last_sent_largest_acked_; + + // Latched value of quic_deprecate_ack_bundling_mode and + // quic_rpm_decides_when_to_send_acks. + const bool decide_when_to_send_acks_; }; } // namespace quic
diff --git a/net/third_party/quic/core/quic_received_packet_manager_test.cc b/net/third_party/quic/core/quic_received_packet_manager_test.cc index e68f864..18d5627 100644 --- a/net/third_party/quic/core/quic_received_packet_manager_test.cc +++ b/net/third_party/quic/core/quic_received_packet_manager_test.cc
@@ -8,14 +8,40 @@ #include <ostream> #include <vector> +#include "net/third_party/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quic/core/quic_connection_stats.h" #include "net/third_party/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quic/platform/api/quic_test.h" +#include "net/third_party/quic/test_tools/mock_clock.h" namespace quic { namespace test { + +class QuicReceivedPacketManagerPeer { + public: + static void SetAckMode(QuicReceivedPacketManager* manager, AckMode ack_mode) { + manager->ack_mode_ = ack_mode; + } + + static void SetFastAckAfterQuiescence(QuicReceivedPacketManager* manager, + bool fast_ack_after_quiescence) { + manager->fast_ack_after_quiescence_ = fast_ack_after_quiescence; + } + + static void SetAckDecimationDelay(QuicReceivedPacketManager* manager, + float ack_decimation_delay) { + manager->ack_decimation_delay_ = ack_decimation_delay; + } +}; + namespace { +const bool kInstigateAck = true; +const QuicTime::Delta kMinRttMs = QuicTime::Delta::FromMilliseconds(40); +const QuicTime::Delta kDelayedAckTime = + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + struct TestParams { explicit TestParams(QuicTransportVersion version) : version(version) {} @@ -40,6 +66,8 @@ class QuicReceivedPacketManagerTest : public QuicTestWithParam<TestParams> { protected: QuicReceivedPacketManagerTest() : received_manager_(&stats_) { + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + rtt_stats_.UpdateRtt(kMinRttMs, QuicTime::Delta::Zero(), QuicTime::Zero()); received_manager_.set_save_timestamps(true); } @@ -53,6 +81,31 @@ received_manager_.RecordPacketReceived(header, receipt_time); } + bool HasPendingAck() { + DCHECK(received_manager_.decide_when_to_send_acks()); + return received_manager_.ack_timeout().IsInitialized(); + } + + void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, + uint64_t last_received_packet_number) { + DCHECK(received_manager_.decide_when_to_send_acks()); + received_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks, + QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(), + clock_.ApproximateNow(), &rtt_stats_, kDelayedAckTime); + } + + void CheckAckTimeout(QuicTime time) { + DCHECK(HasPendingAck() && received_manager_.ack_timeout() == time); + if (time <= clock_.ApproximateNow()) { + // ACK timeout expires, send an ACK. + received_manager_.ResetAckStates(); + DCHECK(!HasPendingAck()); + } + } + + MockClock clock_; + RttStats rtt_stats_; QuicConnectionStats stats_; QuicReceivedPacketManager received_manager_; }; @@ -83,6 +136,9 @@ EXPECT_TRUE(received_manager_.ack_frame_updated()); QuicFrame ack = received_manager_.GetUpdatedAckFrame(QuicTime::Zero()); + if (received_manager_.decide_when_to_send_acks()) { + received_manager_.ResetAckStates(); + } EXPECT_FALSE(received_manager_.ack_frame_updated()); // When UpdateReceivedPacketInfo with a time earlier than the time of the // largest observed packet, make sure that the delta is 0, not negative. @@ -91,6 +147,9 @@ QuicTime four_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(4); ack = received_manager_.GetUpdatedAckFrame(four_ms); + if (received_manager_.decide_when_to_send_acks()) { + received_manager_.ResetAckStates(); + } EXPECT_FALSE(received_manager_.ack_frame_updated()); // When UpdateReceivedPacketInfo after not having received a new packet, // the delta should still be accurate. @@ -107,6 +166,9 @@ received_manager_.RecordPacketReceived(header, two_ms); EXPECT_TRUE(received_manager_.ack_frame_updated()); ack = received_manager_.GetUpdatedAckFrame(two_ms); + if (received_manager_.decide_when_to_send_acks()) { + received_manager_.ResetAckStates(); + } EXPECT_FALSE(received_manager_.ack_frame_updated()); // UpdateReceivedPacketInfo should discard any times which can't be // expressed on the wire. @@ -198,6 +260,548 @@ EXPECT_FALSE(received_manager_.HasMissingPackets()); } +TEST_P(QuicReceivedPacketManagerTest, OutOfOrderReceiptCausesAckSent) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } else { + // Should ack immediately since we have missing packets. + CheckAckTimeout(clock_.ApproximateNow()); + } + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + // Should ack immediately, since this fills the last hole. + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 4); + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); +} + +TEST_P(QuicReceivedPacketManagerTest, OutOfOrderAckReceiptCausesNoAck) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 2); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 1); + EXPECT_FALSE(HasPendingAck()); +} + +TEST_P(QuicReceivedPacketManagerTest, AckReceiptCausesAckSend) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 1); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 2); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 4); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(5, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 5); + EXPECT_FALSE(HasPendingAck()); +} + +TEST_P(QuicReceivedPacketManagerTest, AckSentEveryNthPacket) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + received_manager_.set_ack_frequency_before_ack_decimation(3); + + // Receives packets 1 - 39. + for (size_t i = 1; i <= 39; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 3 == 0) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } +} + +TEST_P(QuicReceivedPacketManagerTest, AckDecimationReducesAcks) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, + ACK_DECIMATION_WITH_REORDERING); + + // Start ack decimation from 10th packet. + received_manager_.set_min_received_before_ack_decimation(10); + + // Receives packets 1 - 29. + for (size_t i = 1; i <= 29; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i <= 10) { + // For packets 1-10, ack every 2 packets. + if (i % 2 == 0) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + continue; + } + // ack at 20. + if (i == 20) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kMinRttMs * 0.25); + } + } + + // We now receive the 30th packet, and so we send an ack. + RecordPacketReceipt(30, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 30); + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_P(QuicReceivedPacketManagerTest, SendDelayedAfterQuiescence) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_, + true); + // The beginning of the connection counts as quiescence. + QuicTime ack_time = + clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + CheckAckTimeout(clock_.ApproximateNow()); + + // Process another packet immediately after sending the ack and expect the + // ack timeout to be set delayed ack time in the future. + ack_time = clock_.ApproximateNow() + kDelayedAckTime; + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + CheckAckTimeout(ack_time); +} + +TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimation) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); + // The ack time should be based on min_rtt * 1/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_P(QuicReceivedPacketManagerTest, + SendDelayedAckAckDecimationAfterQuiescence) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); + QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_, + true); + // The beginning of the connection counts as quiescence. + QuicTime ack_time = + clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + CheckAckTimeout(clock_.ApproximateNow()); + + // Process another packet immedately after sending the ack and expect the + // ack timeout to be set delayed ack time in the future. + ack_time = clock_.ApproximateNow() + kDelayedAckTime; + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + CheckAckTimeout(ack_time); + // Process enough packets to get into ack decimation behavior. + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + EXPECT_FALSE(HasPendingAck()); + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(ack_time); +} + +TEST_P(QuicReceivedPacketManagerTest, + SendDelayedAckDecimationUnlimitedAggregation) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kACKD); + // No limit on the number of packets received before sending an ack. + connection_options.push_back(kAKDU); + config.SetConnectionOptionsToSend(connection_options); + received_manager_.SetFromConfig(config, Perspective::IS_CLIENT); + + // 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() + kMinRttMs * 0.25; + + // Process all the initial packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // 18 packets will not cause an ack to be sent. 19 will because when + // stop waiting frames are in use, we ack every 20 packets no matter what. + for (int i = 1; i <= 18; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(ack_time); +} + +TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); + QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, + 0.125); + + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, + ACK_DECIMATION_WITH_REORDERING); + + // 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() + kMinRttMs * 0.25; + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + // Receive one packet out of order and then the rest in order. + // The loop leaves a one packet gap between acks sent to simulate some loss. + for (int j = 0; j < 3; ++j) { + // Process packet 10 first and ensure the timeout is one eighth min_rtt. + RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11), + clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 0; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11), + clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, + kFirstDecimatedPacket + i + (j * 11)); + } + CheckAckTimeout(clock_.ApproximateNow()); + } +} + +TEST_P(QuicReceivedPacketManagerTest, + SendDelayedAckDecimationWithLargeReordering) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, + ACK_DECIMATION_WITH_REORDERING); + // 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() + kMinRttMs * 0.25; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); + ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // The next packet received in order will cause an immediate ack, because it + // fills a hole. + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_P(QuicReceivedPacketManagerTest, + SendDelayedAckDecimationWithReorderingEighthRtt) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, + ACK_DECIMATION_WITH_REORDERING); + QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, + 0.125); + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // Process packet 10 first and ensure the timeout is one eighth min_rtt. + RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_P(QuicReceivedPacketManagerTest, + SendDelayedAckDecimationWithLargeReorderingEighthRtt) { + if (!received_manager_.decide_when_to_send_acks()) { + return; + } + EXPECT_FALSE(HasPendingAck()); + QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, + ACK_DECIMATION_WITH_REORDERING); + QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, + 0.125); + + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // The next packet received in order will cause an immediate ack, because it + // fills a hole. + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(clock_.ApproximateNow()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.cc b/net/third_party/quic/core/quic_sent_packet_manager.cc index 46047f0ae..a20a7490c 100644 --- a/net/third_party/quic/core/quic_sent_packet_manager.cc +++ b/net/third_party/quic/core/quic_sent_packet_manager.cc
@@ -90,7 +90,6 @@ &general_loss_algorithm_)), general_loss_algorithm_(loss_type), uber_loss_algorithm_(loss_type), - n_connection_simulation_(false), consecutive_rto_count_(0), consecutive_tlp_count_(0), consecutive_crypto_retransmission_count_(0), @@ -189,9 +188,6 @@ if (config.HasClientSentConnectionOption(k1CON, perspective)) { send_algorithm_->SetNumEmulatedConnections(1); } - if (config.HasClientSentConnectionOption(kNCON, perspective)) { - n_connection_simulation_ = true; - } if (config.HasClientSentConnectionOption(kNTLP, perspective)) { max_tail_loss_probes_ = 0; } @@ -262,14 +258,6 @@ } } -void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) { - if (n_connection_simulation_) { - // Ensure the number of connections is between 1 and 5. - send_algorithm_->SetNumEmulatedConnections( - std::min<size_t>(5, std::max<size_t>(1, num_streams))); - } -} - void QuicSentPacketManager::SetHandshakeConfirmed() { handshake_confirmed_ = true; if (unacked_packets_.use_uber_loss_algorithm()) {
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.h b/net/third_party/quic/core/quic_sent_packet_manager.h index 2bbc1e4d..8e34977 100644 --- a/net/third_party/quic/core/quic_sent_packet_manager.h +++ b/net/third_party/quic/core/quic_sent_packet_manager.h
@@ -104,8 +104,6 @@ const CachedNetworkParameters& cached_network_params, bool max_bandwidth_resumption); - void SetNumOpenStreams(size_t num_streams); - void SetMaxPacingRate(QuicBandwidth max_pacing_rate) { pacing_sender_.set_max_pacing_rate(max_pacing_rate); } @@ -511,7 +509,6 @@ // quic_use_uber_loss_algorithm. GeneralLossAlgorithm general_loss_algorithm_; UberLossAlgorithm uber_loss_algorithm_; - bool n_connection_simulation_; // Tracks the first RTO packet. If any packet before that packet gets acked, // it indicates the RTO was spurious and should be reversed(F-RTO).
diff --git a/net/third_party/quic/core/quic_sent_packet_manager_test.cc b/net/third_party/quic/core/quic_sent_packet_manager_test.cc index 9e0fcea88..141f77b 100644 --- a/net/third_party/quic/core/quic_sent_packet_manager_test.cc +++ b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
@@ -2029,23 +2029,6 @@ manager_.SetFromConfig(client_config); } -TEST_P(QuicSentPacketManagerTest, NegotiateNConnectionFromOptions) { - // By default, changing the number of open streams does nothing. - manager_.SetNumOpenStreams(5); - - QuicConfig config; - QuicTagVector options; - - options.push_back(kNCON); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - manager_.SetFromConfig(config); - - EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5)); - manager_.SetNumOpenStreams(5); -} - TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { QuicConfig config; QuicTagVector options;
diff --git a/net/third_party/quic/core/quic_session.cc b/net/third_party/quic/core/quic_session.cc index 281e28c9..85492e2 100644 --- a/net/third_party/quic/core/quic_session.cc +++ b/net/third_party/quic/core/quic_session.cc
@@ -717,8 +717,6 @@ } stream->OnClose(); - // Decrease the number of streams being emulated when a new one is opened. - connection_->SetNumOpenStreams(dynamic_stream_map_.size()); if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst && connection_->transport_version() != QUIC_VERSION_99) { @@ -750,8 +748,6 @@ v99_streamid_manager_.OnStreamClosed(stream_id); } - // Decrease the number of streams being emulated when a new one is opened. - connection_->SetNumOpenStreams(dynamic_stream_map_.size()); OnCanCreateNewOutgoingStream(); } @@ -1020,9 +1016,6 @@ if (IsIncomingStream(stream_id)) { ++num_dynamic_incoming_streams_; } - - // Increase the number of streams being emulated when a new one is opened. - connection_->SetNumOpenStreams(dynamic_stream_map_.size()); } QuicStreamId QuicSession::GetNextOutgoingBidirectionalStreamId() {
diff --git a/net/third_party/quic/core/quic_session_test.cc b/net/third_party/quic/core/quic_session_test.cc index 830ab0e..0fac9f4 100644 --- a/net/third_party/quic/core/quic_session_test.cc +++ b/net/third_party/quic/core/quic_session_test.cc
@@ -439,7 +439,8 @@ path_frame_buffer2_({8, 9, 10, 11, 12, 13, 14, 15}), client_framer_(SupportedVersions(GetParam()), QuicTime::Zero(), - Perspective::IS_CLIENT) { + Perspective::IS_CLIENT, + kQuicDefaultConnectionIdLength) { client_framer_.set_visitor(&framer_visitor_); }
diff --git a/net/third_party/quic/core/quic_time_wait_list_manager.cc b/net/third_party/quic/core/quic_time_wait_list_manager.cc index 8c5be034..6dddb705 100644 --- a/net/third_party/quic/core/quic_time_wait_list_manager.cc +++ b/net/third_party/quic/core/quic_time_wait_list_manager.cc
@@ -162,6 +162,17 @@ if (connection_data->encryption_level == ENCRYPTION_NONE) { QUIC_CODE_COUNT( quic_encryption_none_termination_packets_for_short_header); + if (GetQuicReloadableFlag(quic_always_reset_short_header_packets)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_always_reset_short_header_packets); + // Send stateless reset in response to short header packets, + // because ENCRYPTION_NONE termination packets will not be + // processed by clients. + SendPublicReset(self_address, peer_address, connection_id, + connection_data->ietf_quic, + std::move(packet_context)); + return; + } } else if (connection_data->encryption_level == ENCRYPTION_ZERO_RTT) { QUIC_CODE_COUNT(quic_zero_rtt_termination_packets_for_short_header); }
diff --git a/net/third_party/quic/core/quic_time_wait_list_manager_test.cc b/net/third_party/quic/core/quic_time_wait_list_manager_test.cc index 7e7190be..b0343a7 100644 --- a/net/third_party/quic/core/quic_time_wait_list_manager_test.cc +++ b/net/third_party/quic/core/quic_time_wait_list_manager_test.cc
@@ -202,7 +202,7 @@ const testing::tuple<const char*, int>& packet_buffer) { FramerVisitorCapturingPublicReset visitor(expected_connection_id); QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), - Perspective::IS_CLIENT); + Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); framer.set_visitor(&visitor); QuicEncryptedPacket encrypted(testing::get<0>(packet_buffer), testing::get<1>(packet_buffer)); @@ -542,6 +542,42 @@ } } +// Regression test for b/116200989. +TEST_F(QuicTimeWaitListManagerTest, + SendStatelessResetInResponseToShortHeaders) { + // This test mimics a scenario where an ENCRYPTION_NONE connection close is + // added as termination packet for an IETF connection ID. However, a short + // header packet is received later. + const size_t kConnectionCloseLength = 100; + EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); + std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; + termination_packets.push_back( + std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket( + new char[kConnectionCloseLength], kConnectionCloseLength, true))); + // Add an ENCRYPTION_NONE termination packet. + time_wait_list_manager_.AddConnectionIdToTimeWait( + connection_id_, /*ietf_quic=*/true, + QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_NONE, + &termination_packets); + + if (GetQuicReloadableFlag(quic_always_reset_short_header_packets)) { + // Termination packet is not encrypted, instead, send stateless reset. + EXPECT_CALL(writer_, + WritePacket(_, _, self_address_.host(), peer_address_, _)) + .With(Args<0, 1>(PublicResetPacketEq(connection_id_))) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + } else { + // An unprocessable connection close is sent to peer. + EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, + self_address_.host(), peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + } + // Processes IETF short header packet. + time_wait_list_manager_.ProcessPacket( + self_address_, peer_address_, connection_id_, + IETF_QUIC_SHORT_HEADER_PACKET, QuicMakeUnique<QuicPerPacketContext>()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/net/third_party/quic/core/quic_types.h b/net/third_party/quic/core/quic_types.h index 1b51124..6d35146 100644 --- a/net/third_party/quic/core/quic_types.h +++ b/net/third_party/quic/core/quic_types.h
@@ -575,6 +575,8 @@ NUM_PACKET_NUMBER_SPACES, }; +enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING }; + } // namespace quic #endif // NET_THIRD_PARTY_QUIC_CORE_QUIC_TYPES_H_
diff --git a/net/third_party/quic/core/quic_utils.cc b/net/third_party/quic/core/quic_utils.cc index a8f4689..583a1fa0 100644 --- a/net/third_party/quic/core/quic_utils.cc +++ b/net/third_party/quic/core/quic_utils.cc
@@ -357,10 +357,7 @@ // static bool QuicUtils::IsIetfPacketShortHeader(uint8_t first_byte) { - if (first_byte & FLAGS_LONG_HEADER) { - return false; - } - return !(first_byte & FLAGS_DEMULTIPLEXING_BIT); + return IsIetfPacketHeader(first_byte) && !(first_byte & FLAGS_LONG_HEADER); } // static
diff --git a/net/third_party/quic/core/quic_version_manager.h b/net/third_party/quic/core/quic_version_manager.h index 5b00f07..e7a6b6f 100644 --- a/net/third_party/quic/core/quic_version_manager.h +++ b/net/third_party/quic/core/quic_version_manager.h
@@ -13,6 +13,8 @@ // Used to generate filtered supported versions based on flags. class QUIC_EXPORT_PRIVATE QuicVersionManager { public: + // |supported_versions| should be sorted in the order of preference (typically + // highest supported version to the lowest supported version). explicit QuicVersionManager(ParsedQuicVersionVector supported_versions); virtual ~QuicVersionManager(); @@ -20,7 +22,8 @@ // TODO(nharper): Remove this method once it is unused. const QuicTransportVersionVector& GetSupportedTransportVersions(); - // Returns currently supported QUIC versions. + // Returns currently supported QUIC versions. This vector has the same order + // as the versions passed to the constructor. const ParsedQuicVersionVector& GetSupportedVersions(); protected:
diff --git a/net/third_party/quic/core/tls_handshaker.cc b/net/third_party/quic/core/tls_handshaker.cc index df0c07a7..120c678 100644 --- a/net/third_party/quic/core/tls_handshaker.cc +++ b/net/third_party/quic/core/tls_handshaker.cc
@@ -8,7 +8,6 @@ #include "net/third_party/quic/core/tls_client_handshaker.h" #include "net/third_party/quic/platform/api/quic_arraysize.h" #include "net/third_party/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quic/platform/api/quic_singleton.h" #include "third_party/boringssl/src/include/openssl/crypto.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -19,7 +18,8 @@ class SslIndexSingleton { public: static SslIndexSingleton* GetInstance() { - return QuicSingleton<SslIndexSingleton>::get(); + static SslIndexSingleton* instance = new SslIndexSingleton(); + return instance; } int HandshakerIndex() const { return ssl_ex_data_index_handshaker_; } @@ -35,8 +35,6 @@ SslIndexSingleton(const SslIndexSingleton&) = delete; SslIndexSingleton& operator=(const SslIndexSingleton&) = delete; - friend QuicSingletonFriend<SslIndexSingleton>; - int ssl_ex_data_index_handshaker_; };
diff --git a/net/third_party/quic/platform/api/quic_default_buffer_allocator.h b/net/third_party/quic/platform/api/quic_default_buffer_allocator.h new file mode 100644 index 0000000..abd37de --- /dev/null +++ b/net/third_party/quic/platform/api/quic_default_buffer_allocator.h
@@ -0,0 +1,16 @@ +// Copyright (c) 2019 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 NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_DEFAULT_BUFFER_ALLOCATOR_H_ +#define NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_DEFAULT_BUFFER_ALLOCATOR_H_ + +#include "net/third_party/quic/platform/impl/quic_default_buffer_allocator_impl.h" + +namespace quic { + +using QuicDefaultBufferAllocator = QuicStreamBufferAllocatorImpl; + +} + +#endif // NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_DEFAULT_BUFFER_ALLOCATOR_H_
diff --git a/net/third_party/quic/platform/api/quic_system_event_loop.h b/net/third_party/quic/platform/api/quic_system_event_loop.h index 3a3c6f4..24ae4f8b 100644 --- a/net/third_party/quic/platform/api/quic_system_event_loop.h +++ b/net/third_party/quic/platform/api/quic_system_event_loop.h
@@ -11,4 +11,6 @@ QuicRunSystemEventLoopIterationImpl(); } +using QuicSystemEventLoop = QuicSystemEventLoopImpl; + #endif // NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_SYSTEM_EVENT_LOOP_H_
diff --git a/net/third_party/quic/platform/impl/quic_default_buffer_allocator_impl.h b/net/third_party/quic/platform/impl/quic_default_buffer_allocator_impl.h new file mode 100644 index 0000000..aa9170af --- /dev/null +++ b/net/third_party/quic/platform/impl/quic_default_buffer_allocator_impl.h
@@ -0,0 +1,13 @@ +#ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_DEFAULT_BUFFER_ALLOCATOR_IMPL_H_ +#define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_DEFAULT_BUFFER_ALLOCATOR_IMPL_H_ + +#include "net/third_party/quic/core/quic_simple_buffer_allocator.h" + +namespace quic { + +using QuicStreamBufferAllocatorImpl = SimpleBufferAllocator; + +} // namespace quic + +#endif /* NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_DEFAULT_BUFFER_ALLOCATOR_IMPL_H_ \ + */
diff --git a/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc b/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc index 83ab721..22f1b5e 100644 --- a/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc +++ b/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc
@@ -6,7 +6,7 @@ #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_test.h" -#include "net/third_party/quic/test_tools/fake_epoll_server.h" +#include "net/tools/epoll_server/fake_epoll_server.h" namespace quic { namespace test {
diff --git a/net/third_party/quic/platform/impl/quic_epoll_test_tools_impl.h b/net/third_party/quic/platform/impl/quic_epoll_test_tools_impl.h index 2670140..02b49832 100644 --- a/net/third_party/quic/platform/impl/quic_epoll_test_tools_impl.h +++ b/net/third_party/quic/platform/impl/quic_epoll_test_tools_impl.h
@@ -5,7 +5,7 @@ #ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_EPOLL_TEST_TOOLS_IMPL_H_ #define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_EPOLL_TEST_TOOLS_IMPL_H_ -#include "net/third_party/quic/test_tools/fake_epoll_server.h" +#include "net/tools/epoll_server/fake_epoll_server.h" using QuicFakeEpollServerImpl = quic::test::FakeEpollServer;
diff --git a/net/third_party/quic/platform/impl/quic_socket_address_impl.cc b/net/third_party/quic/platform/impl/quic_socket_address_impl.cc index ea710bf..34f0bdbf 100644 --- a/net/third_party/quic/platform/impl/quic_socket_address_impl.cc +++ b/net/third_party/quic/platform/impl/quic_socket_address_impl.cc
@@ -31,8 +31,11 @@ } QuicSocketAddressImpl::QuicSocketAddressImpl(const struct sockaddr& saddr) { - QUIC_BUG << "QuicSocketAddressImpl(const struct sockaddr& saddr) is not " - "implemented."; + if (saddr.sa_family == AF_INET) { + CHECK(socket_address_.FromSockAddr(&saddr, sizeof(struct sockaddr_in))); + } else if (saddr.sa_family == AF_INET6) { + CHECK(socket_address_.FromSockAddr(&saddr, sizeof(struct sockaddr_in6))); + } } bool operator==(const QuicSocketAddressImpl& lhs,
diff --git a/net/third_party/quic/platform/impl/quic_socket_utils.h b/net/third_party/quic/platform/impl/quic_socket_utils.h index 51809b2..2169589 100644 --- a/net/third_party/quic/platform/impl/quic_socket_utils.h +++ b/net/third_party/quic/platform/impl/quic_socket_utils.h
@@ -19,6 +19,9 @@ #include "net/third_party/quic/core/quic_bandwidth.h" #include "net/third_party/quic/core/quic_types.h" +#define MMSG_MORE 0 +#define MMSG_MORE_NO_ANDROID 0 + namespace quic { class QuicIpAddress; class QuicSocketAddress;
diff --git a/net/third_party/quic/platform/impl/quic_system_event_loop_impl.h b/net/third_party/quic/platform/impl/quic_system_event_loop_impl.h index 0d35bf9..654a48b8d 100644 --- a/net/third_party/quic/platform/impl/quic_system_event_loop_impl.h +++ b/net/third_party/quic/platform/impl/quic_system_event_loop_impl.h
@@ -5,10 +5,22 @@ #ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_SYSTEM_EVENT_LOOP_IMPL_H_ #define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_SYSTEM_EVENT_LOOP_IMPL_H_ +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/task/task_scheduler/task_scheduler.h" inline void QuicRunSystemEventLoopIterationImpl() { base::RunLoop().RunUntilIdle(); } +class QuicSystemEventLoopImpl { + public: + QuicSystemEventLoopImpl(std::string context_name) { + base::TaskScheduler::CreateAndStartWithDefaultParams(context_name); + } + + private: + base::MessageLoopForIO message_loop_; +}; + #endif // NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_SYSTEM_EVENT_LOOP_IMPL_H_
diff --git a/net/third_party/quic/quartc/quartc_dispatcher.cc b/net/third_party/quic/quartc/quartc_dispatcher.cc index fa7b0ac..587395d5 100644 --- a/net/third_party/quic/quartc/quartc_dispatcher.cc +++ b/net/third_party/quic/quartc/quartc_dispatcher.cc
@@ -4,6 +4,7 @@ #include "net/third_party/quic/quartc/quartc_dispatcher.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/core/quic_versions.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/quartc/quartc_factory.h" @@ -25,7 +26,8 @@ version_manager, std::move(helper), std::move(session_helper), - std::move(alarm_factory)), + std::move(alarm_factory), + kQuicDefaultConnectionIdLength), owned_quic_config_(std::move(config)), owned_crypto_config_(std::move(crypto_config)), crypto_config_(crypto_config_serialized),
diff --git a/net/third_party/quic/quartc/quartc_endpoint.h b/net/third_party/quic/quartc/quartc_endpoint.h index 0cedad2..647c326a 100644 --- a/net/third_party/quic/quartc/quartc_endpoint.h +++ b/net/third_party/quic/quartc/quartc_endpoint.h
@@ -148,6 +148,10 @@ return crypto_config_.serialized_crypto_config; } + const std::vector<ParsedQuicVersion> GetSupportedQuicVersions() const { + return version_manager_->GetSupportedVersions(); + } + private: // Implementation of QuicAlarmFactory used by this endpoint. Unowned. QuicAlarmFactory* alarm_factory_;
diff --git a/net/third_party/quic/quartc/quartc_endpoint_test.cc b/net/third_party/quic/quartc/quartc_endpoint_test.cc index 4a1aaa18..b557712 100644 --- a/net/third_party/quic/quartc/quartc_endpoint_test.cc +++ b/net/third_party/quic/quartc/quartc_endpoint_test.cc
@@ -80,7 +80,8 @@ // Tests that the server can negotiate for an older QUIC version if the client // attempts to connect using a newer version. -TEST_F(QuartcEndpointTest, DISABLED_ServerNegotiatesForOldVersion) { +TEST_F(QuartcEndpointTest, + QUIC_TEST_DISABLED_IN_CHROME(ServerNegotiatesForOldVersion)) { // Note: for this test, we need support for two versions. Which two shouldn't // matter, but they must be enabled so that the version manager doesn't filter // them out. @@ -124,7 +125,8 @@ // Tests that the server can accept connections from clients that use older // QUIC versions. -TEST_F(QuartcEndpointTest, DISABLED_ServerAcceptsOldVersion) { +TEST_F(QuartcEndpointTest, + QUIC_TEST_DISABLED_IN_CHROME(ServerAcceptsOldVersion)) { // Note: for this test, we need support for two versions. Which two shouldn't // matter, but they must be enabled so that the version manager doesn't filter // them out. @@ -168,7 +170,7 @@ // Tests that version negotiation fails when the client and server support // completely disjoint sets of versions. -TEST_F(QuartcEndpointTest, VersionNegotiationWithDisjointVersions) { +TEST_F(QuartcEndpointTest, DISABLED_VersionNegotiationWithDisjointVersions) { // Note: for this test, we need support for two versions. Which two shouldn't // matter, but they must be enabled so that the version manager doesn't filter // them out.
diff --git a/net/third_party/quic/quartc/quartc_factory.cc b/net/third_party/quic/quartc/quartc_factory.cc index e0f148939..010527d4 100644 --- a/net/third_party/quic/quartc/quartc_factory.cc +++ b/net/third_party/quic/quartc/quartc_factory.cc
@@ -48,13 +48,7 @@ server_crypto_config); } -QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { - // TODO(b/124398962): Figure out a better way to initialize QUIC flags. - // Creating a config shouldn't have global side-effects on flags. However, - // this has the advantage of ensuring that flag values stay in sync with the - // options requested by configs, so simply splitting the config and flag - // settings doesn't seem preferable. - +void ConfigureGlobalQuicSettings() { // Fixes behavior of StopReading() with level-triggered stream sequencers. SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); @@ -82,16 +76,43 @@ SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, false); SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, false); - QuicTagVector copt; - copt.push_back(kNSTP); - // Enable and request QUIC to include receive timestamps in ACK frames. SetQuicReloadableFlag(quic_send_timestamps, true); - copt.push_back(kSTMP); // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be // false. SetQuicReloadableFlag(quic_enable_ack_decimation, false); + + // Note: flag settings have no effect for Exoblaze builds since + // SetQuicReloadableFlag() gets stubbed out. + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); // Enable BBR6,7,8. + SetQuicReloadableFlag(quic_unified_iw_options, true); // Enable IWXX opts. + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Enable BBQX opts. + SetQuicReloadableFlag(quic_bbr_flexible_app_limited, true); // Enable BBR9. +} + +QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { + // TODO(b/124398962): Figure out a better way to initialize QUIC flags. + // Creating a config shouldn't have global side-effects on flags. However, + // this has the advantage of ensuring that flag values stay in sync with the + // options requested by configs, so simply splitting the config and flag + // settings doesn't seem preferable. + ConfigureGlobalQuicSettings(); + + // In exoblaze this may return false. DCHECK to avoid problems caused by + // incorrect flags configuration. + DCHECK(GetQuicReloadableFlag(quic_enable_version_46)) + << "Your build does not support quic reloadable flags and shouldn't " + "place Quartc calls"; + + QuicTagVector copt; + copt.push_back(kNSTP); + + // Enable and request QUIC to include receive timestamps in ACK frames. + copt.push_back(kSTMP); + + // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be + // false. copt.push_back(kAKD2); // Use unlimited decimation in order to reduce number of unbundled ACKs. @@ -100,12 +121,6 @@ // Enable time-based loss detection. copt.push_back(kTIME); - // Note: flag settings have no effect for Exoblaze builds since - // SetQuicReloadableFlag() gets stubbed out. - SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); // Enable BBR6,7,8. - SetQuicReloadableFlag(quic_unified_iw_options, true); // Enable IWXX opts. - SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Enable BBQX opts. - SetQuicReloadableFlag(quic_bbr_flexible_app_limited, true); // Enable BBR9. copt.push_back(kBBR3); // Stay in low-gain until in-flight < BDP. copt.push_back(kBBR5); // 40 RTT ack aggregation. copt.push_back(kBBR6); // Use a 0.75 * BDP cwnd during PROBE_RTT.
diff --git a/net/third_party/quic/quartc/quartc_factory.h b/net/third_party/quic/quartc/quartc_factory.h index 87acf91..bd00286f 100644 --- a/net/third_party/quic/quartc/quartc_factory.h +++ b/net/third_party/quic/quartc/quartc_factory.h
@@ -85,6 +85,11 @@ std::unique_ptr<QuicCryptoServerStream::Helper> stream_helper_; }; +// Configures global settings, such as supported quic versions. +// Must execute on QUIC thread. +void ConfigureGlobalQuicSettings(); + +// Must execute on QUIC thread. QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config); std::unique_ptr<QuicConnection> CreateQuicConnection(
diff --git a/net/third_party/quic/test_tools/mock_quic_dispatcher.cc b/net/third_party/quic/test_tools/mock_quic_dispatcher.cc index 7a6bf87..0db624aa 100644 --- a/net/third_party/quic/test_tools/mock_quic_dispatcher.cc +++ b/net/third_party/quic/test_tools/mock_quic_dispatcher.cc
@@ -23,7 +23,8 @@ std::move(helper), std::move(session_helper), std::move(alarm_factory), - quic_simple_server_backend) {} + quic_simple_server_backend, + kQuicDefaultConnectionIdLength) {} MockQuicDispatcher::~MockQuicDispatcher() {}
diff --git a/net/third_party/quic/test_tools/quic_connection_peer.cc b/net/third_party/quic/test_tools/quic_connection_peer.cc index 2443523e..fa9c0ce 100644 --- a/net/third_party/quic/test_tools/quic_connection_peer.cc +++ b/net/third_party/quic/test_tools/quic_connection_peer.cc
@@ -257,21 +257,35 @@ // static void QuicConnectionPeer::SetAckMode(QuicConnection* connection, - QuicConnection::AckMode ack_mode) { - connection->ack_mode_ = ack_mode; + AckMode ack_mode) { + if (connection->received_packet_manager_.decide_when_to_send_acks()) { + connection->received_packet_manager_.ack_mode_ = ack_mode; + } else { + connection->ack_mode_ = ack_mode; + } } // static void QuicConnectionPeer::SetFastAckAfterQuiescence( QuicConnection* connection, bool fast_ack_after_quiescence) { - connection->fast_ack_after_quiescence_ = fast_ack_after_quiescence; + if (connection->received_packet_manager_.decide_when_to_send_acks()) { + connection->received_packet_manager_.fast_ack_after_quiescence_ = + fast_ack_after_quiescence; + } else { + connection->fast_ack_after_quiescence_ = fast_ack_after_quiescence; + } } // static void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection, float ack_decimation_delay) { - connection->ack_decimation_delay_ = ack_decimation_delay; + if (connection->received_packet_manager_.decide_when_to_send_acks()) { + connection->received_packet_manager_.ack_decimation_delay_ = + ack_decimation_delay; + } else { + connection->ack_decimation_delay_ = ack_decimation_delay; + } } // static
diff --git a/net/third_party/quic/test_tools/quic_connection_peer.h b/net/third_party/quic/test_tools/quic_connection_peer.h index 6aede1d..c7b06b5 100644 --- a/net/third_party/quic/test_tools/quic_connection_peer.h +++ b/net/third_party/quic/test_tools/quic_connection_peer.h
@@ -116,8 +116,7 @@ QuicPacketCount packets); static void SetNextMtuProbeAt(QuicConnection* connection, QuicPacketNumber number); - static void SetAckMode(QuicConnection* connection, - QuicConnection::AckMode ack_mode); + static void SetAckMode(QuicConnection* connection, AckMode ack_mode); static void SetFastAckAfterQuiescence(QuicConnection* connection, bool fast_ack_after_quiescence); static void SetAckDecimationDelay(QuicConnection* connection,
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.cc b/net/third_party/quic/test_tools/quic_framer_peer.cc index e6d7798..817e3587 100644 --- a/net/third_party/quic/test_tools/quic_framer_peer.cc +++ b/net/third_party/quic/test_tools/quic_framer_peer.cc
@@ -347,5 +347,13 @@ QuicPacketNumber(packet_number); } +// static +void QuicFramerPeer::SetExpectedConnectionIDLength( + QuicFramer* framer, + uint8_t expected_connection_id_length) { + *const_cast<uint8_t*>(&framer->expected_connection_id_length_) = + expected_connection_id_length; +} + } // namespace test } // namespace quic
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.h b/net/third_party/quic/test_tools/quic_framer_peer.h index 24934cdc..8b909157 100644 --- a/net/third_party/quic/test_tools/quic_framer_peer.h +++ b/net/third_party/quic/test_tools/quic_framer_peer.h
@@ -165,6 +165,9 @@ QuicPacketNumberLength packet_number_length); static void SetFirstSendingPacketNumber(QuicFramer* framer, uint64_t packet_number); + static void SetExpectedConnectionIDLength( + QuicFramer* framer, + uint8_t expected_connection_id_length); }; } // namespace test
diff --git a/net/third_party/quic/test_tools/quic_test_server.cc b/net/third_party/quic/test_tools/quic_test_server.cc index e75fd0b..ce30d9a 100644 --- a/net/third_party/quic/test_tools/quic_test_server.cc +++ b/net/third_party/quic/test_tools/quic_test_server.cc
@@ -76,14 +76,16 @@ std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, - QuicSimpleServerBackend* quic_simple_server_backend) + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length) : QuicSimpleDispatcher(config, crypto_config, version_manager, std::move(helper), std::move(session_helper), std::move(alarm_factory), - quic_simple_server_backend), + quic_simple_server_backend, + expected_connection_id_length), session_factory_(nullptr), stream_factory_(nullptr), crypto_stream_factory_(nullptr) {} @@ -157,11 +159,24 @@ const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend) + : QuicTestServer(std::move(proof_source), + config, + supported_versions, + quic_simple_server_backend, + kQuicDefaultConnectionIdLength) {} + +QuicTestServer::QuicTestServer( + std::unique_ptr<ProofSource> proof_source, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length) : QuicServer(std::move(proof_source), config, QuicCryptoServerConfig::ConfigOptions(), supported_versions, - quic_simple_server_backend) {} + quic_simple_server_backend, + expected_connection_id_length) {} QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { return new QuicTestDispatcher( @@ -170,7 +185,8 @@ QuicAllocator::BUFFER_POOL), std::unique_ptr<QuicCryptoServerStream::Helper>( new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())), - QuicMakeUnique<QuicEpollAlarmFactory>(epoll_server()), server_backend()); + QuicMakeUnique<QuicEpollAlarmFactory>(epoll_server()), server_backend(), + expected_connection_id_length()); } void QuicTestServer::SetSessionFactory(SessionFactory* factory) {
diff --git a/net/third_party/quic/test_tools/quic_test_server.h b/net/third_party/quic/test_tools/quic_test_server.h index 1282ef9..3faf7ed 100644 --- a/net/third_party/quic/test_tools/quic_test_server.h +++ b/net/third_party/quic/test_tools/quic_test_server.h
@@ -65,6 +65,11 @@ const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend); + QuicTestServer(std::unique_ptr<ProofSource> proof_source, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length); // Create a custom dispatcher which creates custom sessions. QuicDispatcher* CreateQuicDispatcher() override;
diff --git a/net/third_party/quic/test_tools/quic_test_utils.cc b/net/third_party/quic/test_tools/quic_test_utils.cc index 0c7151e5..12aadd8 100644 --- a/net/third_party/quic/test_tools/quic_test_utils.cc +++ b/net/third_party/quic/test_tools/quic_test_utils.cc
@@ -855,7 +855,8 @@ } QuicFrames frames; - QuicFramer framer(*versions, QuicTime::Zero(), perspective); + QuicFramer framer(*versions, QuicTime::Zero(), perspective, + kQuicDefaultConnectionIdLength); if ((*versions)[0].transport_version < QUIC_VERSION_47) { QuicFrame frame(QuicStreamFrame( QuicUtils::GetCryptoStreamId((*versions)[0].transport_version), false, @@ -913,7 +914,8 @@ QuicFrames frames; frames.push_back(frame); QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(), - QuicTime::Zero(), perspective); + QuicTime::Zero(), perspective, + kQuicDefaultConnectionIdLength); std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames));
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.cc b/net/third_party/quic/test_tools/simple_quic_framer.cc index 2718eeda..fa11fa94 100644 --- a/net/third_party/quic/test_tools/simple_quic_framer.cc +++ b/net/third_party/quic/test_tools/simple_quic_framer.cc
@@ -292,16 +292,23 @@ SimpleQuicFramer::SimpleQuicFramer() : framer_(AllSupportedVersions(), QuicTime::Zero(), - Perspective::IS_SERVER) {} + Perspective::IS_SERVER, + kQuicDefaultConnectionIdLength) {} SimpleQuicFramer::SimpleQuicFramer( const ParsedQuicVersionVector& supported_versions) - : framer_(supported_versions, QuicTime::Zero(), Perspective::IS_SERVER) {} + : framer_(supported_versions, + QuicTime::Zero(), + Perspective::IS_SERVER, + kQuicDefaultConnectionIdLength) {} SimpleQuicFramer::SimpleQuicFramer( const ParsedQuicVersionVector& supported_versions, Perspective perspective) - : framer_(supported_versions, QuicTime::Zero(), perspective) {} + : framer_(supported_versions, + QuicTime::Zero(), + perspective, + kQuicDefaultConnectionIdLength) {} SimpleQuicFramer::~SimpleQuicFramer() {}
diff --git a/net/third_party/quic/test_tools/simulator/actor.cc b/net/third_party/quic/test_tools/simulator/actor.cc index 98aaca6..a217531b 100644 --- a/net/third_party/quic/test_tools/simulator/actor.cc +++ b/net/third_party/quic/test_tools/simulator/actor.cc
@@ -12,10 +12,12 @@ : simulator_(simulator), clock_(simulator->GetClock()), name_(std::move(name)) { - simulator->AddActor(this); + simulator_->AddActor(this); } -Actor::~Actor() {} +Actor::~Actor() { + simulator_->RemoveActor(this); +} void Actor::Schedule(QuicTime next_tick) { simulator_->Schedule(this, next_tick);
diff --git a/net/third_party/quic/test_tools/simulator/simulator.cc b/net/third_party/quic/test_tools/simulator/simulator.cc index 5a5154c..74c56b1d 100644 --- a/net/third_party/quic/test_tools/simulator/simulator.cc +++ b/net/third_party/quic/test_tools/simulator/simulator.cc
@@ -19,7 +19,11 @@ alarm_factory_.CreateAlarm(new RunForDelegate(&run_for_should_stop_))); } -Simulator::~Simulator() {} +Simulator::~Simulator() { + // Ensure that Actor under run_for_alarm_ is removed before Simulator data + // structures are destructed. + run_for_alarm_.reset(); +} Simulator::Clock::Clock() : now_(kStartTime) {} @@ -46,6 +50,21 @@ DCHECK(emplace_names_result.second); } +void Simulator::RemoveActor(Actor* actor) { + auto scheduled_time_it = scheduled_times_.find(actor); + auto actor_names_it = actor_names_.find(actor->name()); + DCHECK(scheduled_time_it != scheduled_times_.end()); + DCHECK(actor_names_it != actor_names_.end()); + + QuicTime scheduled_time = scheduled_time_it->second; + if (scheduled_time != QuicTime::Infinite()) { + Unschedule(actor); + } + + scheduled_times_.erase(scheduled_time_it); + actor_names_.erase(actor_names_it); +} + void Simulator::Schedule(Actor* actor, QuicTime new_time) { auto scheduled_time_it = scheduled_times_.find(actor); DCHECK(scheduled_time_it != scheduled_times_.end());
diff --git a/net/third_party/quic/test_tools/simulator/simulator.h b/net/third_party/quic/test_tools/simulator/simulator.h index 74ed03a..3ea2b438 100644 --- a/net/third_party/quic/test_tools/simulator/simulator.h +++ b/net/third_party/quic/test_tools/simulator/simulator.h
@@ -26,10 +26,6 @@ Simulator& operator=(const Simulator&) = delete; ~Simulator() override; - // Register an actor with the simulator. Returns a handle which the actor can - // use to schedule and unschedule itself. - void AddActor(Actor* actor); - // Schedule the specified actor. This method will ensure that |actor| is // called at |new_time| at latest. If Schedule() is called multiple times // before the Actor is called, Act() is called exactly once, at the earliest @@ -70,6 +66,8 @@ void RunFor(QuicTime::Delta time_span); private: + friend class Actor; + class Clock : public QuicClock { public: // Do not start at zero as certain code can treat zero as an invalid @@ -97,6 +95,12 @@ bool* run_for_should_stop_; }; + // Register an actor with the simulator. Invoked by Actor constructor. + void AddActor(Actor* actor); + + // Unregister an actor with the simulator. Invoked by Actor destructor. + void RemoveActor(Actor* actor); + // Finds the next scheduled actor, advances time to the schedule time and // notifies the actor. void HandleNextScheduledActor();
diff --git a/net/third_party/quic/test_tools/simulator/simulator_test.cc b/net/third_party/quic/test_tools/simulator/simulator_test.cc index fdda91cb..92f329d 100644 --- a/net/third_party/quic/test_tools/simulator/simulator_test.cc +++ b/net/third_party/quic/test_tools/simulator/simulator_test.cc
@@ -48,19 +48,22 @@ class SimulatorTest : public QuicTest {}; -// Test that the basic event handling works. +// Test that the basic event handling works, and that Actors can be created and +// destroyed mid-simulation. TEST_F(SimulatorTest, Counters) { Simulator simulator; - Counter fast_counter(&simulator, "fast_counter", - QuicTime::Delta::FromSeconds(3)); - Counter slow_counter(&simulator, "slow_counter", - QuicTime::Delta::FromSeconds(10)); + for (int i = 0; i < 2; ++i) { + Counter fast_counter(&simulator, "fast_counter", + QuicTime::Delta::FromSeconds(3)); + Counter slow_counter(&simulator, "slow_counter", + QuicTime::Delta::FromSeconds(10)); - simulator.RunUntil( - [&slow_counter]() { return slow_counter.get_value() >= 10; }); + simulator.RunUntil( + [&slow_counter]() { return slow_counter.get_value() >= 10; }); - EXPECT_EQ(10, slow_counter.get_value()); - EXPECT_EQ(10 * 10 / 3, fast_counter.get_value()); + EXPECT_EQ(10, slow_counter.get_value()); + EXPECT_EQ(10 * 10 / 3, fast_counter.get_value()); + } } // A port which counts the number of packets received on it, both total and
diff --git a/net/third_party/quic/tools/quic_client_bin.cc b/net/third_party/quic/tools/quic_client_bin.cc index 86bc7ad5..1d14fda 100644 --- a/net/third_party/quic/tools/quic_client_bin.cc +++ b/net/third_party/quic/tools/quic_client_bin.cc
@@ -8,100 +8,143 @@ // // Some usage examples: // -// TODO(rtenneti): make --host optional by getting IP Address of URL's host. -// -// Get IP address of the www.google.com -// IP=`dig www.google.com +short | head -1` -// // Standard request/response: -// quic_client http://www.google.com --host=${IP} -// quic_client http://www.google.com --quiet --host=${IP} -// quic_client https://www.google.com --port=443 --host=${IP} +// quic_client www.google.com +// quic_client www.google.com --quiet +// quic_client www.google.com --port=443 // // Use a specific version: -// quic_client http://www.google.com --quic_version=23 --host=${IP} +// quic_client www.google.com --quic_version=23 // // Send a POST instead of a GET: -// quic_client http://www.google.com --body="this is a POST body" --host=${IP} +// quic_client www.google.com --body="this is a POST body" // // Append additional headers to the request: -// quic_client http://www.google.com --host=${IP} -// --headers="Header-A: 1234; Header-B: 5678" +// quic_client www.google.com --headers="Header-A: 1234; Header-B: 5678" // // Connect to a host different to the URL being requested: -// Get IP address of the www.google.com +// quic_client mail.google.com --host=www.google.com +// +// Connect to a specific IP: // IP=`dig www.google.com +short | head -1` -// quic_client mail.google.com --host=${IP} +// quic_client www.google.com --host=${IP} // // Send repeated requests and change ephemeral port between requests // quic_client www.google.com --num_requests=10 // // Try to connect to a host which does not speak QUIC: -// Get IP address of the www.example.com -// IP=`dig www.example.com +short | head -1` -// quic_client http://www.example.com --host=${IP} +// quic_client www.example.com + +#include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> #include <iostream> +#include <memory> #include <vector> -#include "base/at_exit.h" -#include "base/command_line.h" -#include "base/message_loop/message_loop.h" -#include "base/task/task_scheduler/task_scheduler.h" -#include "net/base/net_errors.h" -#include "net/base/privacy_mode.h" #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_server_id.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_default_proof_providers.h" -#include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/platform/api/quic_socket_address.h" #include "net/third_party/quic/platform/api/quic_str_cat.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quic/platform/api/quic_system_event_loop.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" #include "net/third_party/quic/tools/quic_client.h" #include "net/third_party/quic/tools/quic_url.h" -#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" -#include "net/tools/epoll_server/epoll_server.h" -#include "net/tools/quic/synchronous_host_resolver.h" -using quic::ProofVerifier; +namespace { + +using quic::QuicSocketAddress; using quic::QuicString; using quic::QuicStringPiece; using quic::QuicTextUtils; using quic::QuicUrl; -using spdy::SpdyHeaderBlock; -using std::cerr; -using std::cout; -using std::endl; -using std::string; + +class FakeProofVerifier : public quic::ProofVerifier { + public: + ~FakeProofVerifier() override {} + quic::QuicAsyncStatus VerifyProof( + const std::string& /*hostname*/, + const uint16_t /*port*/, + const std::string& /*server_config*/, + quic::QuicTransportVersion /*quic_version*/, + quic::QuicStringPiece /*chlo_hash*/, + const std::vector<std::string>& /*certs*/, + const std::string& /*cert_sct*/, + const std::string& /*signature*/, + const quic::ProofVerifyContext* /*context*/, + std::string* /*error_details*/, + std::unique_ptr<quic::ProofVerifyDetails>* /*details*/, + std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { + return quic::QUIC_SUCCESS; + } + quic::QuicAsyncStatus VerifyCertChain( + const std::string& /*hostname*/, + const std::vector<std::string>& /*certs*/, + const quic::ProofVerifyContext* /*context*/, + std::string* /*error_details*/, + std::unique_ptr<quic::ProofVerifyDetails>* /*details*/, + std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { + return quic::QUIC_SUCCESS; + } + std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } +}; + +QuicSocketAddress LookupAddress(QuicString host, QuicString port) { + addrinfo hint; + memset(&hint, 0, sizeof(hint)); + hint.ai_protocol = IPPROTO_UDP; + + addrinfo* info_list = nullptr; + int result = getaddrinfo(host.c_str(), port.c_str(), &hint, &info_list); + if (result != 0) { + QUIC_LOG(ERROR) << "Failed to look up " << host << ": " + << gai_strerror(result); + return QuicSocketAddress(); + } + + CHECK(info_list != nullptr); + std::unique_ptr<addrinfo, void (*)(addrinfo*)> info_list_owned(info_list, + freeaddrinfo); + return QuicSocketAddress(*info_list->ai_addr); +} + +} // namespace DEFINE_QUIC_COMMAND_LINE_FLAG( - string, + std::string, host, "", - "The IP or hostname the quic client will connect to."); + "The IP or hostname to connect to. If not provided, the host " + "will be derived from the provided URL."); DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to."); -DEFINE_QUIC_COMMAND_LINE_FLAG(string, +DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, body, "", "If set, send a POST with this body."); DEFINE_QUIC_COMMAND_LINE_FLAG( - string, + std::string, body_hex, "", - "If set, contents are converted from hex to ascii, before sending as body " - "of a POST. e.g. --body_hex=\"68656c6c6f\""); + "If set, contents are converted from hex to ascii, before " + "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\""); DEFINE_QUIC_COMMAND_LINE_FLAG( - string, + std::string, headers, "", - "A semicolon separated list of key:value pairs to add to request headers."); + "A semicolon separated list of key:value pairs to " + "add to request headers."); DEFINE_QUIC_COMMAND_LINE_FLAG(bool, quiet, @@ -112,23 +155,23 @@ int32_t, quic_version, -1, - "QUIC version to speak, e.g. 21. If not set, then all available versions " - "are offered in the handshake."); + "QUIC version to speak, e.g. 21. If not set, then all available " + "versions are offered in the handshake."); DEFINE_QUIC_COMMAND_LINE_FLAG( bool, version_mismatch_ok, false, - "If true, a version mismatch in the handshake is not considered a failure. " - "Useful for probing a server to determine if it speaks any version of " - "QUIC."); + "If true, a version mismatch in the handshake is not considered a " + "failure. Useful for probing a server to determine if it speaks " + "any version of QUIC."); DEFINE_QUIC_COMMAND_LINE_FLAG( bool, redirect_is_success, true, - "If true, an HTTP response code of 3xx is considered to be a successful " - "response, otherwise a failure."); + "If true, an HTTP response code of 3xx is considered to be a " + "successful response, otherwise a failure."); DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, initial_mtu, @@ -141,84 +184,31 @@ 1, "How many sequential requests to make on a single connection."); +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + disable_certificate_verification, + false, + "If true, don't verify the server certificate."); + DEFINE_QUIC_COMMAND_LINE_FLAG( bool, drop_response_body, false, "If true, drop response body immediately after it is received."); -DEFINE_QUIC_COMMAND_LINE_FLAG(bool, - disable_certificate_verification, - false, - "If true, do not verify certificates."); - -class FakeProofVerifier : public ProofVerifier { - public: - quic::QuicAsyncStatus VerifyProof( - const string& /*hostname*/, - const uint16_t /*port*/, - const string& /*server_config*/, - quic::QuicTransportVersion /*quic_version*/, - QuicStringPiece /*chlo_hash*/, - const std::vector<string>& /*certs*/, - const string& /*cert_sct*/, - const string& /*signature*/, - const quic::ProofVerifyContext* /*context*/, - string* /*error_details*/, - std::unique_ptr<quic::ProofVerifyDetails>* /*details*/, - std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { - return quic::QUIC_SUCCESS; - } - - quic::QuicAsyncStatus VerifyCertChain( - const std::string& /*hostname*/, - const std::vector<std::string>& /*certs*/, - const quic::ProofVerifyContext* /*verify_context*/, - std::string* /*error_details*/, - std::unique_ptr<quic::ProofVerifyDetails>* /*verify_details*/, - std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { - return quic::QUIC_SUCCESS; - } - std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override { - return nullptr; - } -}; - int main(int argc, char* argv[]) { - base::TaskScheduler::CreateAndStartWithDefaultParams("quic_client"); - const char* usage = - "Usage: epoll_quic_client [options] <url>\n" - "\n" - "<url> with scheme must be provided (e.g. http://www.google.com)\n"; + QuicSystemEventLoop event_loop("quic_client"); + const char* usage = "Usage: quic_client [options] <url>"; + + // All non-flag arguments should be interpreted as URLs to fetch. std::vector<QuicString> urls = quic::QuicParseCommandLineFlags(usage, argc, argv); - if (urls.empty()) { + if (urls.size() != 1) { quic::QuicPrintCommandLineFlagHelp(usage); exit(0); } - logging::LoggingSettings settings; - settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; - CHECK(logging::InitLogging(settings)); - - VLOG(1) << "server host: " << GetQuicFlag(FLAGS_host) - << " port: " << GetQuicFlag(FLAGS_port) - << " body: " << GetQuicFlag(FLAGS_body) - << " headers: " << GetQuicFlag(FLAGS_headers) - << " quiet: " << GetQuicFlag(FLAGS_quiet) - << " quic-version: " << GetQuicFlag(FLAGS_quic_version) - << " version_mismatch_ok: " << GetQuicFlag(FLAGS_version_mismatch_ok) - << " redirect_is_success: " << GetQuicFlag(FLAGS_redirect_is_success) - << " initial_mtu: " << GetQuicFlag(FLAGS_initial_mtu); - - base::AtExitManager exit_manager; - base::MessageLoopForIO message_loop; - - // Determine IP address to connect to from supplied hostname. - quic::QuicIpAddress ip_addr; - QuicUrl url(urls[0], "https"); - string host = GetQuicFlag(FLAGS_host); + std::string host = GetQuicFlag(FLAGS_host); if (host.empty()) { host = url.host(); } @@ -226,20 +216,14 @@ if (port == 0) { port = url.port(); } - if (!ip_addr.FromString(host)) { - net::AddressList addresses; - int rv = net::SynchronousHostResolver::Resolve(host, &addresses); - if (rv != net::OK) { - LOG(ERROR) << "Unable to resolve '" << host - << "' : " << net::ErrorToShortString(rv); - return 1; - } - ip_addr = - quic::QuicIpAddress(quic::QuicIpAddressImpl(addresses[0].address())); - } - string host_port = quic::QuicStrCat(ip_addr.ToString(), ":", port); - VLOG(1) << "Resolved " << host << " to " << host_port << endl; + // Determine IP address to connect to from supplied hostname. + QuicSocketAddress addr = LookupAddress(host, quic::QuicStrCat(port)); + if (!addr.IsInitialized()) { + return 1; + } + std::cerr << "Resolved " << url.ToString() << " to " << addr.ToString() + << std::endl; // Build the client, and try to connect. quic::QuicEpollServer epoll_server; @@ -251,42 +235,41 @@ quic::PROTOCOL_QUIC_CRYPTO, static_cast<quic::QuicTransportVersion>( GetQuicFlag(FLAGS_quic_version)))); } - const int32_t num_requests = GetQuicFlag(FLAGS_num_requests); - // For secure QUIC we need to verify the cert chain. - std::unique_ptr<ProofVerifier> proof_verifier; + const int32_t num_requests(GetQuicFlag(FLAGS_num_requests)); + std::unique_ptr<quic::ProofVerifier> proof_verifier; if (GetQuicFlag(FLAGS_disable_certificate_verification)) { proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>(); } else { proof_verifier = quic::CreateDefaultProofVerifier(); } - quic::QuicClient client(quic::QuicSocketAddress(ip_addr, port), server_id, - versions, &epoll_server, std::move(proof_verifier)); - client.set_initial_max_packet_length(GetQuicFlag(FLAGS_initial_mtu) != 0 - ? GetQuicFlag(FLAGS_initial_mtu) - : quic::kDefaultMaxPacketSize); + quic::QuicClient client(addr, server_id, versions, &epoll_server, + std::move(proof_verifier)); + int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu); + client.set_initial_max_packet_length( + initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize); client.set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body)); if (!client.Initialize()) { - cerr << "Failed to initialize client." << endl; + std::cerr << "Failed to initialize client." << std::endl; return 1; } if (!client.Connect()) { quic::QuicErrorCode error = client.session()->error(); if (error == quic::QUIC_INVALID_VERSION) { - cout << "Server talks QUIC, but none of the versions supported by " - << "this client: " << ParsedQuicVersionVectorToString(versions) - << endl; + std::cerr << "Server talks QUIC, but none of the versions supported by " + << "this client: " << ParsedQuicVersionVectorToString(versions) + << std::endl; // 0: No error. // 20: Failed to connect due to QUIC_INVALID_VERSION. return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20; } - cerr << "Failed to connect to " << host_port - << ". Error: " << quic::QuicErrorCodeToString(error) << endl; + std::cerr << "Failed to connect to " << addr.ToString() + << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl; return 1; } - cout << "Connected to " << host_port << endl; + std::cerr << "Connected to " << addr.ToString() << std::endl; // Construct the string body from flags, if provided. - string body = GetQuicFlag(FLAGS_body); + std::string body = GetQuicFlag(FLAGS_body); if (!GetQuicFlag(FLAGS_body_hex).empty()) { DCHECK(GetQuicFlag(FLAGS_body).empty()) << "Only set one of --body and --body_hex."; @@ -322,62 +305,67 @@ // Print request and response details. if (!GetQuicFlag(FLAGS_quiet)) { - cout << "Request:" << endl; - cout << "headers:" << header_block.DebugString(); + std::cout << "Request:" << std::endl; + std::cout << "headers:" << header_block.DebugString(); if (!GetQuicFlag(FLAGS_body_hex).empty()) { // Print the user provided hex, rather than binary body. - cout << "body:\n" - << QuicTextUtils::HexDump( - QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex))) - << endl; + std::cout << "body:\n" + << QuicTextUtils::HexDump( + QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex))) + << std::endl; } else { - cout << "body: " << body << endl; + std::cout << "body: " << body << std::endl; } - cout << endl; + std::cout << std::endl; if (!client.preliminary_response_headers().empty()) { - cout << "Preliminary response headers: " - << client.preliminary_response_headers() << endl; - cout << endl; + std::cout << "Preliminary response headers: " + << client.preliminary_response_headers() << std::endl; + std::cout << std::endl; } - cout << "Response:" << endl; - cout << "headers: " << client.latest_response_headers() << endl; - string response_body = client.latest_response_body(); + std::cout << "Response:" << std::endl; + std::cout << "headers: " << client.latest_response_headers() << std::endl; + std::string response_body = client.latest_response_body(); if (!GetQuicFlag(FLAGS_body_hex).empty()) { // Assume response is binary data. - cout << "body:\n" << QuicTextUtils::HexDump(response_body) << endl; + std::cout << "body:\n" + << QuicTextUtils::HexDump(response_body) << std::endl; } else { - cout << "body: " << response_body << endl; + std::cout << "body: " << response_body << std::endl; } - cout << "trailers: " << client.latest_response_trailers() << endl; + std::cout << "trailers: " << client.latest_response_trailers() + << std::endl; } if (!client.connected()) { - cerr << "Request caused connection failure. Error: " - << quic::QuicErrorCodeToString(client.session()->error()) << endl; + std::cerr << "Request caused connection failure. Error: " + << quic::QuicErrorCodeToString(client.session()->error()) + << std::endl; return 1; } size_t response_code = client.latest_response_code(); if (response_code >= 200 && response_code < 300) { - cout << "Request succeeded (" << response_code << ")." << endl; + std::cerr << "Request succeeded (" << response_code << ")." << std::endl; } else if (response_code >= 300 && response_code < 400) { if (GetQuicFlag(FLAGS_redirect_is_success)) { - cout << "Request succeeded (redirect " << response_code << ")." << endl; + std::cerr << "Request succeeded (redirect " << response_code << ")." + << std::endl; } else { - cout << "Request failed (redirect " << response_code << ")." << endl; + std::cerr << "Request failed (redirect " << response_code << ")." + << std::endl; return 1; } } else { - cerr << "Request failed (" << response_code << ")." << endl; + std::cerr << "Request failed (" << response_code << ")." << std::endl; return 1; } // Change the ephemeral port if there are more requests to do. if (i + 1 < num_requests) { if (!client.ChangeEphemeralPort()) { - cout << "Failed to change ephemeral port." << endl; + std::cerr << "Failed to change ephemeral port." << std::endl; return 1; } }
diff --git a/net/third_party/quic/tools/quic_packet_printer_bin.cc b/net/third_party/quic/tools/quic_packet_printer_bin.cc index ef3cde47..b6ba7a9 100644 --- a/net/third_party/quic/tools/quic_packet_printer_bin.cc +++ b/net/third_party/quic/tools/quic_packet_printer_bin.cc
@@ -12,48 +12,31 @@ // Usage: quic_packet_printer server|client <hex dump of packet> // // Example input: -// quic_packet_printer server 0c6b810308320f24c004a939a38a2e3fd6ca589917f200400 -// 201b80b0100501c0700060003023d0000001c00556e656e637279707465642073747265616d2 -// 064617461207365656e +// quic_packet_printer server 0c6b810308320f24c004a939a38a2e3fd6ca589917f200400201b80b0100501c0700060003023d0000001c00556e656e637279707465642073747265616d2064617461207365656e // // Example output: // OnPacket // OnUnauthenticatedPublicHeader -// OnUnauthenticatedHeader: { connection_id: 13845207862000976235, -// connection_id_length:8, packet_number_length:1, multipath_flag: 0, -// reset_flag: 0, version_flag: 0, path_id: , packet_number: 4} +// OnUnauthenticatedHeader: { connection_id: 13845207862000976235, connection_id_length:8, packet_number_length:1, multipath_flag: 0, reset_flag: 0, version_flag: 0, path_id: , packet_number: 4 } // OnDecryptedPacket // OnPacketHeader -// OnAckFrame: largest_observed: 1 ack_delay_time: 3000 -// missing_packets: [ ] is_truncated: 0 received_packets: [ 1 at 466016 ] +// OnAckFrame: largest_observed: 1 ack_delay_time: 3000 missing_packets: [ ] is_truncated: 0 received_packets: [ 1 at 466016 ] // OnStopWaitingFrame -// OnConnectionCloseFrame: error_code { 61 } error_details { Unencrypted stream -// data seen } +// OnConnectionCloseFrame: error_code { 61 } error_details { Unencrypted stream data seen } // clang-format on #include <iostream> -#include <string> -#include "base/command_line.h" -#include "base/strings/utf_string_conversions.h" #include "net/third_party/quic/core/quic_framer.h" #include "net/third_party/quic/core/quic_utils.h" +#include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -// If set, specify the QUIC version to use. -quic::QuicString FLAGS_quic_version = ""; - -namespace { - -quic::QuicString ArgToString(base::CommandLine::StringType arg) { -#if defined(OS_WIN) - return base::UTF16ToASCII(arg); -#else - return arg; -#endif -} -} // namespace +DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, + quic_version, + "", + "If set, specify the QUIC version to use."); namespace quic { @@ -224,40 +207,36 @@ } // namespace quic int main(int argc, char* argv[]) { - base::CommandLine::Init(argc, argv); - base::CommandLine* line = base::CommandLine::ForCurrentProcess(); - const base::CommandLine::StringVector& args = line->GetArgs(); + const char* usage = "Usage: quic_packet_printer client|server <hex>"; + std::vector<quic::QuicString> args = + quic::QuicParseCommandLineFlags(usage, argc, argv); - if (args.size() != 3) { - std::cerr << "Missing argument " << argc << ". (Usage: " << argv[0] - << " client|server <hex>\n"; + if (args.size() < 2) { + quic::QuicPrintCommandLineFlagHelp(usage); return 1; } - if (line->HasSwitch("quic_version")) { - FLAGS_quic_version = line->GetSwitchValueASCII("quic_version"); - } - - quic::QuicString perspective_string = ArgToString(args[0]); + quic::QuicString perspective_string = args[0]; quic::Perspective perspective; if (perspective_string == "client") { perspective = quic::Perspective::IS_CLIENT; } else if (perspective_string == "server") { perspective = quic::Perspective::IS_SERVER; } else { - std::cerr << "Invalid perspective. " << perspective_string - << " Usage: " << args[0] << " client|server <hex>\n"; + std::cerr << "Invalid perspective" << std::endl; + quic::QuicPrintCommandLineFlagHelp(usage); return 1; } - quic::QuicString hex = quic::QuicTextUtils::HexDecode(argv[2]); + quic::QuicString hex = quic::QuicTextUtils::HexDecode(args[1]); quic::ParsedQuicVersionVector versions = quic::AllSupportedVersions(); // Fake a time since we're not actually generating acks. quic::QuicTime start(quic::QuicTime::Zero()); - quic::QuicFramer framer(versions, start, perspective); - if (!FLAGS_quic_version.empty()) { + quic::QuicFramer framer(versions, start, perspective, + quic::kQuicDefaultConnectionIdLength); + if (!GetQuicFlag(FLAGS_quic_version).empty()) { for (quic::ParsedQuicVersion version : versions) { if (quic::QuicVersionToString(version.transport_version) == - FLAGS_quic_version) { + GetQuicFlag(FLAGS_quic_version)) { framer.set_version(version); } }
diff --git a/net/third_party/quic/tools/quic_reject_reason_decoder_bin.cc b/net/third_party/quic/tools/quic_reject_reason_decoder_bin.cc index 9eaf8f19..c55c071 100644 --- a/net/third_party/quic/tools/quic_reject_reason_decoder_bin.cc +++ b/net/third_party/quic/tools/quic_reject_reason_decoder_bin.cc
@@ -7,28 +7,27 @@ #include <iostream> -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" #include "net/third_party/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quic/platform/api/quic_flags.h" +#include "net/third_party/quic/platform/api/quic_text_utils.h" -using base::CommandLine; -using quic::HandshakeFailureReason; using quic::CryptoUtils; +using quic::HandshakeFailureReason; using quic::MAX_FAILURE_REASON; int main(int argc, char* argv[]) { - CommandLine::Init(argc, argv); - CommandLine* line = CommandLine::ForCurrentProcess(); - const CommandLine::StringVector& args = line->GetArgs(); + const char* usage = "Usage: quic_reject_reason_decoder <packed_reason>"; + std::vector<quic::QuicString> args = + quic::QuicParseCommandLineFlags(usage, argc, argv); if (args.size() != 1) { - std::cerr << "Missing argument (Usage: " << argv[0] << " <packed_reason>\n"; + std::cerr << usage << std::endl; return 1; } uint32_t packed_error = 0; - if (!base::StringToUint(args[0], &packed_error)) { + if (!quic::QuicTextUtils::StringToUint32(args[0], &packed_error)) { std::cerr << "Unable to parse: " << args[0] << "\n"; return 2; }
diff --git a/net/third_party/quic/tools/quic_server.cc b/net/third_party/quic/tools/quic_server.cc index 141b1a4..e51310c 100644 --- a/net/third_party/quic/tools/quic_server.cc +++ b/net/third_party/quic/tools/quic_server.cc
@@ -55,14 +55,16 @@ QuicConfig(), QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions(), - quic_simple_server_backend) {} + quic_simple_server_backend, + kQuicDefaultConnectionIdLength) {} QuicServer::QuicServer( std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, const ParsedQuicVersionVector& supported_versions, - QuicSimpleServerBackend* quic_simple_server_backend) + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length) : port_(0), fd_(-1), packets_dropped_(0), @@ -77,7 +79,8 @@ crypto_config_options_(crypto_config_options), version_manager_(supported_versions), packet_reader_(new QuicPacketReader()), - quic_simple_server_backend_(quic_simple_server_backend) { + quic_simple_server_backend_(quic_simple_server_backend), + expected_connection_id_length_(expected_connection_id_length) { Initialize(); } @@ -155,7 +158,7 @@ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())), std::unique_ptr<QuicEpollAlarmFactory>( new QuicEpollAlarmFactory(&epoll_server_)), - quic_simple_server_backend_); + quic_simple_server_backend_, expected_connection_id_length_); } void QuicServer::WaitForEvents() {
diff --git a/net/third_party/quic/tools/quic_server.h b/net/third_party/quic/tools/quic_server.h index 3f2be0c..caddf20 100644 --- a/net/third_party/quic/tools/quic_server.h +++ b/net/third_party/quic/tools/quic_server.h
@@ -41,7 +41,8 @@ const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& server_config_options, const ParsedQuicVersionVector& supported_versions, - QuicSimpleServerBackend* quic_simple_server_backend); + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length); QuicServer(const QuicServer&) = delete; QuicServer& operator=(const QuicServer&) = delete; @@ -99,6 +100,10 @@ void set_silent_close(bool value) { silent_close_ = value; } + uint8_t expected_connection_id_length() { + return expected_connection_id_length_; + } + private: friend class quic::test::QuicServerPeer; @@ -145,6 +150,9 @@ std::unique_ptr<QuicPacketReader> packet_reader_; QuicSimpleServerBackend* quic_simple_server_backend_; // unowned. + + // Connection ID length expected to be read on incoming IETF short headers. + uint8_t expected_connection_id_length_; }; } // namespace quic
diff --git a/net/third_party/quic/tools/quic_server_bin.cc b/net/third_party/quic/tools/quic_server_bin.cc index a9f6133..7117e94b 100644 --- a/net/third_party/quic/tools/quic_server_bin.cc +++ b/net/third_party/quic/tools/quic_server_bin.cc
@@ -98,7 +98,8 @@ CreateProofSource(base::FilePath(GetQuicFlag(FLAGS_certificate_file)), base::FilePath(GetQuicFlag(FLAGS_key_file))), config, quic::QuicCryptoServerConfig::ConfigOptions(), - quic::AllSupportedVersions(), &memory_cache_backend); + quic::AllSupportedVersions(), &memory_cache_backend, + quic::kQuicDefaultConnectionIdLength); int rc = server.CreateUDPSocketAndListen(quic::QuicSocketAddress( quic::QuicIpAddress::Any6(), GetQuicFlag(FLAGS_port)));
diff --git a/net/third_party/quic/tools/quic_server_test.cc b/net/third_party/quic/tools/quic_server_test.cc index c086d17..15f40d81 100644 --- a/net/third_party/quic/tools/quic_server_test.cc +++ b/net/third_party/quic/tools/quic_server_test.cc
@@ -45,7 +45,8 @@ std::move(helper), std::move(session_helper), std::move(alarm_factory), - quic_simple_server_backend) {} + quic_simple_server_backend, + kQuicDefaultConnectionIdLength) {} ~MockQuicSimpleDispatcher() override = default; MOCK_METHOD0(OnCanWrite, void());
diff --git a/net/third_party/quic/tools/quic_simple_dispatcher.cc b/net/third_party/quic/tools/quic_simple_dispatcher.cc index 73d516c..4df52e8b 100644 --- a/net/third_party/quic/tools/quic_simple_dispatcher.cc +++ b/net/third_party/quic/tools/quic_simple_dispatcher.cc
@@ -15,13 +15,15 @@ std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, - QuicSimpleServerBackend* quic_simple_server_backend) + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length) : QuicDispatcher(config, crypto_config, version_manager, std::move(helper), std::move(session_helper), - std::move(alarm_factory)), + std::move(alarm_factory), + expected_connection_id_length), quic_simple_server_backend_(quic_simple_server_backend) {} QuicSimpleDispatcher::~QuicSimpleDispatcher() = default;
diff --git a/net/third_party/quic/tools/quic_simple_dispatcher.h b/net/third_party/quic/tools/quic_simple_dispatcher.h index 48c39e5..b17080b7a 100644 --- a/net/third_party/quic/tools/quic_simple_dispatcher.h +++ b/net/third_party/quic/tools/quic_simple_dispatcher.h
@@ -20,7 +20,8 @@ std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, - QuicSimpleServerBackend* quic_simple_server_backend); + QuicSimpleServerBackend* quic_simple_server_backend, + uint8_t expected_connection_id_length); ~QuicSimpleDispatcher() override;
diff --git a/net/third_party/quic/test_tools/fake_epoll_server.cc b/net/tools/epoll_server/fake_epoll_server.cc similarity index 96% rename from net/third_party/quic/test_tools/fake_epoll_server.cc rename to net/tools/epoll_server/fake_epoll_server.cc index 48eaef3..e5ab48c 100644 --- a/net/third_party/quic/test_tools/fake_epoll_server.cc +++ b/net/tools/epoll_server/fake_epoll_server.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 "net/third_party/quic/test_tools/fake_epoll_server.h" +#include "net/tools/epoll_server/fake_epoll_server.h" namespace quic { namespace test {
diff --git a/net/third_party/quic/test_tools/fake_epoll_server.h b/net/tools/epoll_server/fake_epoll_server.h similarity index 94% rename from net/third_party/quic/test_tools/fake_epoll_server.h rename to net/tools/epoll_server/fake_epoll_server.h index d3584ec5..8605c43 100644 --- a/net/third_party/quic/test_tools/fake_epoll_server.h +++ b/net/tools/epoll_server/fake_epoll_server.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 NET_THIRD_PARTY_QUIC_TEST_TOOLS_FAKE_EPOLL_SERVER_H_ -#define NET_THIRD_PARTY_QUIC_TEST_TOOLS_FAKE_EPOLL_SERVER_H_ +#ifndef NET_TOOLS_EPOLL_SERVER_FAKE_EPOLL_SERVER_H_ +#define NET_TOOLS_EPOLL_SERVER_FAKE_EPOLL_SERVER_H_ #include <stddef.h> #include <stdint.h> @@ -112,4 +112,4 @@ } // namespace test } // namespace quic -#endif // NET_THIRD_PARTY_QUIC_TEST_TOOLS_FAKE_EPOLL_SERVER_H_ +#endif // NET_TOOLS_EPOLL_SERVER_FAKE_EPOLL_SERVER_H_
diff --git a/net/tools/quic/quic_http_proxy_backend_stream.h b/net/tools/quic/quic_http_proxy_backend_stream.h index a64a1cc3..d415fad 100644 --- a/net/tools/quic/quic_http_proxy_backend_stream.h +++ b/net/tools/quic/quic_http_proxy_backend_stream.h
@@ -55,9 +55,12 @@ class QuicHttpProxyBackend; // An adapter for making HTTP requests to net::URLRequest. +// +// TODO(https://crbug.com/937621): This class does not appear to be thread +// safe, so all its tests are disabled. class QuicHttpProxyBackendStream : public net::URLRequest::Delegate { public: - QuicHttpProxyBackendStream(QuicHttpProxyBackend* context); + explicit QuicHttpProxyBackendStream(QuicHttpProxyBackend* context); ~QuicHttpProxyBackendStream() override; static const std::set<std::string> kHopHeaders;
diff --git a/net/tools/quic/quic_http_proxy_backend_stream_test.cc b/net/tools/quic/quic_http_proxy_backend_stream_test.cc index b0e4372..76cdaf2 100644 --- a/net/tools/quic/quic_http_proxy_backend_stream_test.cc +++ b/net/tools/quic/quic_http_proxy_backend_stream_test.cc
@@ -195,7 +195,8 @@ std::unique_ptr<EmbeddedTestServer> test_server_; }; -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendGetDefault) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendGetDefault) { spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = kDefaultResponsePath; request_headers[":authority"] = "www.example.org"; @@ -214,7 +215,7 @@ EXPECT_EQ(kDefaultResponseBody, quic_response->body()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendGetLarge) { +TEST_F(QuicHttpProxyBackendStreamTest, DISABLED_SendRequestToBackendGetLarge) { spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/defaultresponselarge"; request_headers[":authority"] = "www.example.org"; @@ -235,7 +236,7 @@ EXPECT_EQ(kLargeResponseBody, quic_response->body()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostBody) { +TEST_F(QuicHttpProxyBackendStreamTest, DISABLED_SendRequestToBackendPostBody) { const char kUploadData[] = "bobsyeruncle"; spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/echo"; @@ -258,7 +259,8 @@ EXPECT_EQ(kUploadData, quic_response->body()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostEmptyString) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendPostEmptyString) { const char kUploadData[] = ""; spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/echo"; @@ -281,7 +283,7 @@ EXPECT_EQ(kUploadData, quic_response->body()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostFile) { +TEST_F(QuicHttpProxyBackendStreamTest, DISABLED_SendRequestToBackendPostFile) { std::string kUploadData; base::FilePath upload_path = GetUploadFileTestPath(); ASSERT_TRUE(base::ReadFileToString(upload_path, &kUploadData)); @@ -306,7 +308,8 @@ EXPECT_EQ(kUploadData, quic_response->body()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendResponse500) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendResponse500) { const char kUploadData[] = "bobsyeruncle"; spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/echo?status=500"; @@ -326,7 +329,7 @@ EXPECT_EQ(500, ParseHeaderStatusCode(quic_response->headers())); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendFail) { +TEST_F(QuicHttpProxyBackendStreamTest, DISABLED_SendRequestToBackendFail) { const char kUploadData[] = "bobsyeruncle"; spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/echo"; @@ -345,7 +348,8 @@ quic_response->response_type()); } -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendOnRedirect) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendOnRedirect) { const std::string kRedirectTarget = backend_url_.append("/echo"); spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = std::string("/server-redirect?") + kRedirectTarget; @@ -367,7 +371,8 @@ // Ensure that the proxy rewrites the content-length when receiving a Gzipped // response -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendHandleGzip) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendHandleGzip) { const char kGzipData[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!"; uint64_t rawBodyLength = strlen(kGzipData); @@ -406,7 +411,8 @@ } // Ensure cookies are not saved/updated at the proxy -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendCookiesNotSaved) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendCookiesNotSaved) { spdy::SpdyHeaderBlock request_headers; request_headers[":authority"] = "www.example.org"; request_headers[":method"] = "GET"; @@ -450,7 +456,8 @@ // Ensure hop-by-hop headers are removed from the request and response to the // backend -TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendHopHeaders) { +TEST_F(QuicHttpProxyBackendStreamTest, + DISABLED_SendRequestToBackendHopHeaders) { spdy::SpdyHeaderBlock request_headers; request_headers[":path"] = "/echoall"; request_headers[":authority"] = "www.example.org";
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc index 1ba1ed6..4a72f24d 100644 --- a/net/tools/quic/quic_simple_server.cc +++ b/net/tools/quic/quic_simple_server.cc
@@ -137,7 +137,7 @@ std::unique_ptr<quic::QuicCryptoServerStream::Helper>( new QuicSimpleServerSessionHelper(quic::QuicRandom::GetInstance())), std::unique_ptr<quic::QuicAlarmFactory>(alarm_factory_), - quic_simple_server_backend_)); + quic_simple_server_backend_, quic::kQuicDefaultConnectionIdLength)); QuicSimpleServerPacketWriter* writer = new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get()); dispatcher_->InitializeWithWriter(writer);
diff --git a/net/url_request/http_with_dns_over_https_unittest.cc b/net/url_request/http_with_dns_over_https_unittest.cc index 40971a7..cb877ff 100644 --- a/net/url_request/http_with_dns_over_https_unittest.cc +++ b/net/url_request/http_with_dns_over_https_unittest.cc
@@ -4,10 +4,11 @@ #include "base/bind.h" #include "net/base/proxy_server.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_client.h" #include "net/dns/dns_config.h" #include "net/dns/dns_transaction.h" -#include "net/dns/host_resolver_impl.h" +#include "net/dns/host_resolver_proc.h" #include "net/http/http_stream_factory_test_util.h" #include "net/log/net_log.h" #include "net/socket/transport_client_socket_pool.h" @@ -47,7 +48,7 @@ class HttpWithDnsOverHttpsTest : public TestWithScopedTaskEnvironment { public: HttpWithDnsOverHttpsTest() - : resolver_(HostResolver::Options(), nullptr), + : resolver_(HostResolver::CreateDefaultResolverImpl(nullptr)), request_context_(true), doh_server_(EmbeddedTestServer::Type::TYPE_HTTPS), test_server_(EmbeddedTestServer::Type::TYPE_HTTPS), @@ -67,11 +68,11 @@ config.nameservers.push_back(IPEndPoint()); config.dns_over_https_servers.emplace_back(url.spec(), true /* use_post */); dns_client->SetConfig(config); - resolver_.SetRequestContext(&request_context_); - resolver_.set_proc_params_for_test( - HostResolverImpl::ProcTaskParams(new TestHostResolverProc(), 1)); - resolver_.SetDnsClient(std::move(dns_client)); - request_context_.set_host_resolver(&resolver_); + resolver_->SetRequestContext(&request_context_); + resolver_->SetProcParamsForTesting( + ProcTaskParams(new TestHostResolverProc(), 1)); + resolver_->SetDnsClientForTesting(std::move(dns_client)); + request_context_.set_host_resolver(resolver_.get()); request_context_.Init(); } @@ -119,7 +120,7 @@ } protected: - HostResolverImpl resolver_; + std::unique_ptr<ContextHostResolver> resolver_; TestURLRequestContext request_context_; EmbeddedTestServer doh_server_; EmbeddedTestServer test_server_;
diff --git a/net/url_request/url_request_ftp_fuzzer.cc b/net/url_request/url_request_ftp_fuzzer.cc index 7028b54..c702813 100644 --- a/net/url_request/url_request_ftp_fuzzer.cc +++ b/net/url_request/url_request_ftp_fuzzer.cc
@@ -11,7 +11,7 @@ #include "base/run_loop.h" #include "base/test/fuzzed_data_provider.h" #include "net/base/request_priority.h" -#include "net/dns/fuzzed_host_resolver.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/ftp/ftp_network_transaction.h" #include "net/ftp/ftp_transaction_factory.h" #include "net/socket/client_socket_factory.h" @@ -60,8 +60,8 @@ url_request_context.set_client_socket_factory(&fuzzed_socket_factory); // Need to fuzz the HostResolver to select between IPv4 and IPv6. - net::FuzzedHostResolver host_resolver(net::HostResolver::Options(), nullptr, - &data_provider); + net::FuzzedContextHostResolver host_resolver(net::HostResolver::Options(), + nullptr, &data_provider); url_request_context.set_host_resolver(&host_resolver); net::URLRequestJobFactoryImpl job_factory;
diff --git a/net/websockets/README.md b/net/websockets/README.md index 6cc512c..bd87b1cc0 100644 --- a/net/websockets/README.md +++ b/net/websockets/README.md
@@ -2,3 +2,34 @@ This directory contains the implementation of [the WebSocket protocol](https://tools.ietf.org/html/rfc6455). + +## Design docs + +* [WebSocketBasicHandshakeStream design + memo](https://docs.google.com/document/d/1r7dQDA9AQBD_kOk-z-yMi0WgLQZ-5m7psMO5pYLFUL8/edit). + Some details have changed, but still a mostly-accurate description of + Chromium's current implementation. +* [WebSocket Throttling + Design](https://docs.google.com/document/d/1a8sUFQsbN5uve7ziW61ATkrFr3o9A-Tiyw8ig6T3puA/edit) + discusses how we enforce WebSocket connection throttling. Also contains + detailed discussion of how WebSockets integrate with the socket pools. Dates + from 2014, but still mostly relevant. +* [WebSockets over + HTTP/2](https://docs.google.com/document/d/1ZxaHz4j2BDMa1aI5CQHMjtFI3UxGT459pjYv4To9rFY/edit). + Current as of 2019 description of WebSocket over H/2 implementation. +* [WebSocket + Network Service + WebRequest + API](https://docs.google.com/document/d/1L85aXX-m5NaV-g223lH7kKB2HPg6kMi1cjrDVeEptE8/edit): + design for how extension callbacks are called when the network service is + enabled. +* [WebSocket HTTP Auth + Design](https://docs.google.com/document/d/129rLtf5x3hvhP5rayLiSxnEjOXS8Z7EnLJgBL4CdwjI/edit). + This document is very low on detail, but can serve as an overview of how auth + works for WebSockets. +* [Per-renderer WebSocket + throttling](https://docs.google.com/document/d/1aw2oN5PKfk-1gLnBrlv1OwLA8K3-ykM2ckwX2lubTg4/edit). + While the algorithm described in this document is still used, the code has + moved around significantly due to network servicification. +* [WebSocket Protocol Stack in + chrome/net](https://docs.google.com/document/d/11n3hpwb9lD9YVqnjX3OwzE_jHgTmKIqd6GvXE9bDGUg/edit). + Early design doc for the current implementation. Mostly of historical interest + only.
diff --git a/services/identity/BUILD.gn b/services/identity/BUILD.gn index 41e710a6..8a4ce0a3 100644 --- a/services/identity/BUILD.gn +++ b/services/identity/BUILD.gn
@@ -33,6 +33,7 @@ ":lib", "//base", "//base/test:test_support", + "//components/image_fetcher/core:test_support", "//components/prefs:test_support", "//components/signin/core/browser:internals", "//components/signin/core/browser:internals_test_support",
diff --git a/services/identity/DEPS b/services/identity/DEPS index 9eb4337..76399cc 100644 --- a/services/identity/DEPS +++ b/services/identity/DEPS
@@ -1,9 +1,9 @@ include_rules = [ + "+components/image_fetcher/core/fake_image_decoder.h", "+components/prefs/pref_service.h", "+components/signin/core/browser/account_info.h", "+components/signin/core/browser/account_tracker_service.h", "+components/signin/core/browser/device_id_helper.h", - "+components/signin/core/browser/test_image_decoder.h", "+components/signin/core/browser/fake_profile_oauth2_token_service.h", "+components/signin/core/browser/fake_signin_manager.h", "+components/signin/core/browser/profile_oauth2_token_service.h",
diff --git a/services/identity/identity_accessor_impl.cc b/services/identity/identity_accessor_impl.cc index 659d095..afff7d4 100644 --- a/services/identity/identity_accessor_impl.cc +++ b/services/identity/identity_accessor_impl.cc
@@ -14,35 +14,21 @@ namespace identity { -IdentityAccessorImpl::AccessTokenRequest::AccessTokenRequest( - const std::string& account_id, - const ScopeSet& scopes, - const std::string& consumer_id, +void IdentityAccessorImpl::OnTokenRequestCompleted( + base::UnguessableToken callback_id, + scoped_refptr<base::RefCountedData<bool>> is_callback_done, GetAccessTokenCallback consumer_callback, - IdentityAccessorImpl* manager) - : consumer_callback_(std::move(consumer_callback)), manager_(manager) { - access_token_fetcher_ = - manager->identity_manager_->CreateAccessTokenFetcherForAccount( - account_id, consumer_id, scopes, - base::BindOnce(&AccessTokenRequest::OnTokenRequestCompleted, - base::Unretained(this)), - identity::AccessTokenFetcher::Mode::kImmediate); -} - -IdentityAccessorImpl::AccessTokenRequest::~AccessTokenRequest() = default; - -void IdentityAccessorImpl::AccessTokenRequest::OnTokenRequestCompleted( GoogleServiceAuthError error, AccessTokenInfo access_token_info) { if (error.state() == GoogleServiceAuthError::NONE) { - std::move(consumer_callback_) + std::move(consumer_callback) .Run(access_token_info.token, access_token_info.expiration_time, error); } else { - std::move(consumer_callback_).Run(base::nullopt, base::Time(), error); + std::move(consumer_callback).Run(base::nullopt, base::Time(), error); } - // Causes |this| to be deleted. - manager_->AccessTokenRequestCompleted(this); + is_callback_done->data = true; + access_token_fetchers_.erase(callback_id); } // static @@ -108,12 +94,23 @@ const ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) { - std::unique_ptr<AccessTokenRequest> access_token_request = - std::make_unique<AccessTokenRequest>(account_id, scopes, consumer_id, - std::move(callback), this); + base::UnguessableToken callback_id = base::UnguessableToken::Create(); + auto is_callback_done = + base::MakeRefCounted<base::RefCountedData<bool>>(false); - access_token_requests_[access_token_request.get()] = - std::move(access_token_request); + std::unique_ptr<AccessTokenFetcher> fetcher = + identity_manager_->CreateAccessTokenFetcherForAccount( + account_id, consumer_id, scopes, + base::BindOnce(&IdentityAccessorImpl::OnTokenRequestCompleted, + base::Unretained(this), callback_id, is_callback_done, + std::move(callback)), + identity::AccessTokenFetcher::Mode::kImmediate); + + // If our callback hasn't already been run, hold on to the AccessTokenFetcher + // so it won't be cleaned up until the request is done. + if (!is_callback_done->data) { + access_token_fetchers_[callback_id] = std::move(fetcher); + } } void IdentityAccessorImpl::OnRefreshTokenUpdatedForAccount( @@ -146,11 +143,6 @@ } } -void IdentityAccessorImpl::AccessTokenRequestCompleted( - AccessTokenRequest* request) { - access_token_requests_.erase(request); -} - AccountState IdentityAccessorImpl::GetStateOfAccount( const AccountInfo& account_info) { AccountState account_state;
diff --git a/services/identity/identity_accessor_impl.h b/services/identity/identity_accessor_impl.h index 9a41e62..d055c80d 100644 --- a/services/identity/identity_accessor_impl.h +++ b/services/identity/identity_accessor_impl.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_IDENTITY_IDENTITY_ACCESSOR_IMPL_H_ #define SERVICES_IDENTITY_IDENTITY_ACCESSOR_IMPL_H_ +#include <map> #include <memory> #include "base/callback_list.h" @@ -33,29 +34,18 @@ ~IdentityAccessorImpl() override; private: - // Makes an access token request to the IdentityManager on behalf of a - // given consumer that has made the request to the Identity Service. - class AccessTokenRequest { - public: - AccessTokenRequest(const std::string& account_id, - const ScopeSet& scopes, - const std::string& consumer_id, - GetAccessTokenCallback consumer_callback, - IdentityAccessorImpl* manager); - ~AccessTokenRequest(); + // Map of outstanding access token requests. + using AccessTokenFetchers = + std::map<base::UnguessableToken, std::unique_ptr<AccessTokenFetcher>>; - private: - // Invoked after access token request completes (successful or not). - // Completes the pending access token request by calling back the consumer. - void OnTokenRequestCompleted(GoogleServiceAuthError error, - AccessTokenInfo access_token_info); - - std::unique_ptr<AccessTokenFetcher> access_token_fetcher_; - GetAccessTokenCallback consumer_callback_; - IdentityAccessorImpl* manager_; - }; - using AccessTokenRequests = - std::map<AccessTokenRequest*, std::unique_ptr<AccessTokenRequest>>; + // Invoked after access token request completes (successful or not). + // Completes the pending access token request by calling back the consumer. + void OnTokenRequestCompleted( + base::UnguessableToken callback_id, + scoped_refptr<base::RefCountedData<bool>> is_callback_done, + GetAccessTokenCallback consumer_callback, + GoogleServiceAuthError error, + AccessTokenInfo access_token_info); // mojom::IdentityAccessor: void GetPrimaryAccountInfo(GetPrimaryAccountInfoCallback callback) override; @@ -78,9 +68,6 @@ // corresponding to |account_id|. void OnAccountStateChange(const std::string& account_id); - // Deletes |request|. - void AccessTokenRequestCompleted(AccessTokenRequest* request); - // Gets the current state of the account represented by |account_info|. AccountState GetStateOfAccount(const AccountInfo& account_info); @@ -93,7 +80,7 @@ AccountTrackerService* account_tracker_; // The set of pending requests for access tokens. - AccessTokenRequests access_token_requests_; + AccessTokenFetchers access_token_fetchers_; // List of callbacks that will be notified when the primary account is // available.
diff --git a/services/identity/identity_accessor_impl_unittest.cc b/services/identity/identity_accessor_impl_unittest.cc index f18ac111..30a6a8a3 100644 --- a/services/identity/identity_accessor_impl_unittest.cc +++ b/services/identity/identity_accessor_impl_unittest.cc
@@ -6,11 +6,11 @@ #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "build/build_config.h" +#include "components/image_fetcher/core/fake_image_decoder.h" #include "components/signin/core/browser/account_info.h" #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "services/identity/identity_service.h" @@ -71,9 +71,9 @@ SigninManagerBase::RegisterPrefs(pref_service_.registry()); account_tracker_.Initialize(&pref_service_, base::FilePath()); - account_fetcher_.Initialize(&signin_client_, &token_service_, - &account_tracker_, - std::make_unique<TestImageDecoder>()); + account_fetcher_.Initialize( + &signin_client_, &token_service_, &account_tracker_, + std::make_unique<image_fetcher::FakeImageDecoder>()); signin_manager_.Initialize(&pref_service_); }
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS index 5f3ccaf..008499ed7 100644 --- a/services/identity/public/cpp/DEPS +++ b/services/identity/public/cpp/DEPS
@@ -1,10 +1,10 @@ include_rules = [ + "+components/image_fetcher/core/fake_image_decoder.h", "+components/prefs/testing_pref_service.h", "+components/signin/core/browser/account_consistency_method.h", "+components/signin/core/browser/account_fetcher_service.h", "+components/signin/core/browser/account_info.h", "+components/signin/core/browser/child_account_info_fetcher_android.h", - "+components/signin/core/browser/test_image_decoder.h", "+components/signin/core/browser/gaia_cookie_manager_service.h", "+components/signin/core/browser/list_accounts_test_utils.h", "+components/signin/core/browser/oauth2_token_service_delegate_android.h",
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc index c74f6b67..84dc5f0 100644 --- a/services/identity/public/cpp/identity_manager_unittest.cc +++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -16,13 +16,13 @@ #include "base/stl_util.h" #include "base/test/bind_test_util.h" #include "build/build_config.h" +#include "components/image_fetcher/core/fake_image_decoder.h" #include "components/signin/core/browser/account_consistency_method.h" #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" #include "components/signin/core/browser/list_accounts_test_utils.h" #include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/browser/signin_switches.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -341,9 +341,9 @@ SigninManagerBase::RegisterPrefs(pref_service_.registry()); account_tracker_.Initialize(&pref_service_, base::FilePath()); - account_fetcher_.Initialize(&signin_client_, &token_service_, - &account_tracker_, - std::make_unique<TestImageDecoder>()); + account_fetcher_.Initialize( + &signin_client_, &token_service_, &account_tracker_, + std::make_unique<image_fetcher::FakeImageDecoder>()); RecreateSigninAndIdentityManager( signin::AccountConsistencyMethod::kDisabled,
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc index d2b1c93..2d7dcc4 100644 --- a/services/identity/public/cpp/identity_test_environment.cc +++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -9,11 +9,11 @@ #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" +#include "components/image_fetcher/core/fake_image_decoder.h" #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" #include "components/signin/core/browser/gaia_cookie_manager_service.h" #include "components/signin/core/browser/signin_manager.h" -#include "components/signin/core/browser/test_image_decoder.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" @@ -131,9 +131,9 @@ SigninManagerBase::RegisterPrefs(pref_service()->registry()); account_tracker_.Initialize(pref_service(), base::FilePath()); - account_fetcher_.Initialize(signin_client(), &token_service_, - &account_tracker_, - std::make_unique<TestImageDecoder>()); + account_fetcher_.Initialize( + signin_client(), &token_service_, &account_tracker_, + std::make_unique<image_fetcher::FakeImageDecoder>()); signin_manager_.Initialize(pref_service()); }
diff --git a/services/network/host_resolver_unittest.cc b/services/network/host_resolver_unittest.cc index d80a15a..430f357 100644 --- a/services/network/host_resolver_unittest.cc +++ b/services/network/host_resolver_unittest.cc
@@ -20,10 +20,10 @@ #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_config.h" #include "net/dns/dns_test_util.h" #include "net/dns/host_resolver.h" -#include "net/dns/host_resolver_impl.h" #include "net/dns/mock_host_resolver.h" #include "net/dns/public/dns_protocol.h" #include "net/log/net_log.h" @@ -1145,9 +1145,9 @@ std::make_unique<net::MockDnsClient>(net::DnsConfig(), std::move(rules)); net::NetLog net_log; - std::unique_ptr<net::HostResolverImpl> inner_resolver = + std::unique_ptr<net::ContextHostResolver> inner_resolver = net::HostResolver::CreateDefaultResolverImpl(&net_log); - inner_resolver->SetDnsClient(std::move(dns_client)); + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); inner_resolver->SetBaseDnsConfigForTesting(CreateValidDnsConfig()); HostResolver resolver(inner_resolver.get(), &net_log); @@ -1183,9 +1183,9 @@ std::make_unique<net::MockDnsClient>(net::DnsConfig(), std::move(rules)); net::NetLog net_log; - std::unique_ptr<net::HostResolverImpl> inner_resolver = + std::unique_ptr<net::ContextHostResolver> inner_resolver = net::HostResolver::CreateDefaultResolverImpl(&net_log); - inner_resolver->SetDnsClient(std::move(dns_client)); + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); inner_resolver->SetBaseDnsConfigForTesting(CreateValidDnsConfig()); HostResolver resolver(inner_resolver.get(), &net_log);
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 5eaceb3..79425af07 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -58,8 +58,8 @@ #include "net/cookies/cookie_options.h" #include "net/cookies/cookie_store.h" #include "net/disk_cache/disk_cache.h" +#include "net/dns/context_host_resolver.h" #include "net/dns/dns_test_util.h" -#include "net/dns/host_resolver_impl.h" #include "net/dns/host_resolver_source.h" #include "net/dns/mock_host_resolver.h" #include "net/dns/public/dns_query_type.h" @@ -2917,8 +2917,8 @@ network_context->GetNumOutstandingResolveHostRequestsForTesting()); } -// Test factory of net::HostResolvers. Creates standard net::HostResolverImpl. -// Keeps pointers to all created resolvers. +// Test factory of net::HostResolvers. Creates standard +// net::ContextHostResolver. Keeps pointers to all created resolvers. class TestResolverFactory : public net::HostResolver::Factory { public: static TestResolverFactory* CreateAndSetFactory(NetworkContext* context) { @@ -2931,18 +2931,18 @@ std::unique_ptr<net::HostResolver> CreateResolver( const net::HostResolver::Options& options, net::NetLog* net_log) override { - std::unique_ptr<net::HostResolverImpl> resolver = + std::unique_ptr<net::ContextHostResolver> resolver = net::HostResolver::CreateSystemResolverImpl(options, net_log); resolvers_.push_back(resolver.get()); return resolver; } - const std::vector<net::HostResolverImpl*>& resolvers() const { + const std::vector<net::ContextHostResolver*>& resolvers() const { return resolvers_; } private: - std::vector<net::HostResolverImpl*> resolvers_; + std::vector<net::ContextHostResolver*> resolvers_; }; TEST_F(NetworkContextTest, CreateHostResolver) { @@ -3091,7 +3091,7 @@ // Should create 1 private resolver with a DnsClient (if DnsClient is // enablable for the build config). ASSERT_EQ(1u, factory->resolvers().size()); - net::HostResolverImpl* internal_resolver = factory->resolvers().front(); + net::ContextHostResolver* internal_resolver = factory->resolvers().front(); #if defined(ENABLE_BUILT_IN_DNS) EXPECT_TRUE(internal_resolver->GetDnsConfigAsValue()); #endif @@ -3115,7 +3115,7 @@ auto mock_dns_client = std::make_unique<net::MockDnsClient>(net::DnsConfig(), std::move(rules)); auto* mock_dns_client_ptr = mock_dns_client.get(); - internal_resolver->SetDnsClient(std::move(mock_dns_client)); + internal_resolver->SetDnsClientForTesting(std::move(mock_dns_client)); // Force the base configuration to ensure consistent overriding. net::DnsConfig base_configuration;
diff --git a/services/service_manager/sandbox/mac/common.sb b/services/service_manager/sandbox/mac/common.sb index 579d9de..e2d14db9 100644 --- a/services/service_manager/sandbox/mac/common.sb +++ b/services/service_manager/sandbox/mac/common.sb
@@ -68,10 +68,13 @@ ; https://crbug.com/850021 (define (allow-cvms-blobs) (if (>= os-version 1014) - (allow file-read* - (extension "com.apple.cvms.kernel") - (subpath "/private/var/db/CVMS") - ))) + (begin + (allow file-read* file-write-unlink + (prefix "/private/tmp/cvmsCodeSignObj")) + (allow file-read* + (extension "com.apple.cvms.kernel") + (prefix "/private/var/db/CVMS/cvmsCodeSignObj")) +))) ; Allow logging for all processes. (allow file-write* @@ -191,3 +194,8 @@ (sysctl-name "sysctl.proc_cputype") (sysctl-name (string-append "kern.proc.pid." (param current-pid))) ) + +(allow network-outbound + (literal "/private/var/run/asl_input") + (literal "/private/var/run/syslog") +)
diff --git a/services/service_manager/sandbox/mac/gpu_v2.sb b/services/service_manager/sandbox/mac/gpu_v2.sb index 6a051984..e0aa0a8 100644 --- a/services/service_manager/sandbox/mac/gpu_v2.sb +++ b/services/service_manager/sandbox/mac/gpu_v2.sb
@@ -14,6 +14,7 @@ (global-name "com.apple.CoreServices.coreservicesd") (global-name "com.apple.coreservices.launchservicesd") (global-name "com.apple.cvmsServ") + (global-name "com.apple.gpumemd.source") (global-name "com.apple.system.notification_center") (global-name "com.apple.tsm.uiserver") (global-name "com.apple.windowserver.active") @@ -24,7 +25,10 @@ (iokit-connection "IOAccelerator") (iokit-user-client-class "AGPMClient") (iokit-user-client-class "AppleGraphicsControlClient") + (iokit-user-client-class "AppleGraphicsPolicyClient") + (iokit-user-client-class "AppleIntelMEUserClient") (iokit-user-client-class "AppleMGPUPowerControlClient") + (iokit-user-client-class "AppleSNBFBUserClient") (iokit-user-client-class "IOAccelerationUserClient") (iokit-user-client-class "IOFramebufferSharedUserClient") (iokit-user-client-class "IOHIDParamUserClient") @@ -33,6 +37,16 @@ (iokit-user-client-class "RootDomainUserClient") ) +(allow iokit-set-properties + (require-all (iokit-connection "IODisplay") + (require-any (iokit-property "brightness") + (iokit-property "linear-brightness") + (iokit-property "commit") + (iokit-property "rgcs") + (iokit-property "ggcs") + (iokit-property "bgcs") +))) + (allow ipc-posix-shm-read-data (ipc-posix-name "apple.shm.notification_center")) @@ -51,7 +65,13 @@ (allow sysctl-read (sysctl-name "hw.logicalcpu_max") (sysctl-name "hw.model") + (sysctl-name "kern.osvariant_status") ) (allow file-read-data - (regex (user-homedir-path #"/Library/Preferences/ByHost/com.apple.AppleGVA.*"))) + (regex (user-homedir-path #"/Library/Preferences/ByHost/com.apple.AppleGVA.*")) +) + +(allow file-read* + (subpath "/Library/GPUBundles") +)
diff --git a/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java b/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java index cfdc07f6..5b21176 100644 --- a/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java +++ b/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java
@@ -13,8 +13,10 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Feature; import org.chromium.shape_detection.mojom.BarcodeDetection; +import org.chromium.shape_detection.mojom.BarcodeDetectionProvider; import org.chromium.shape_detection.mojom.BarcodeDetectionResult; import org.chromium.shape_detection.mojom.BarcodeDetectorOptions; +import org.chromium.shape_detection.mojom.BarcodeFormat; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; @@ -27,6 +29,32 @@ private static final org.chromium.skia.mojom.Bitmap QR_CODE_BITMAP = TestUtils.mojoBitmapFromFile("qr_code.png"); + private static final int[] SUPPORTED_FORMATS = {BarcodeFormat.AZTEC, BarcodeFormat.CODE_128, + BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat.CODABAR, + BarcodeFormat.DATA_MATRIX, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8, BarcodeFormat.ITF, + BarcodeFormat.PDF417, BarcodeFormat.QR_CODE, BarcodeFormat.UPC_A, BarcodeFormat.UPC_E}; + + private static int[] enumerateSupportedFormats() { + BarcodeDetectionProvider provider = new BarcodeDetectionProviderImpl(); + + final ArrayBlockingQueue<int[]> queue = new ArrayBlockingQueue<>(13); + provider.enumerateSupportedFormats( + new BarcodeDetectionProvider.EnumerateSupportedFormatsResponse() { + @Override + public void call(int[] results) { + queue.add(results); + } + }); + int[] toReturn = null; + try { + toReturn = queue.poll(5L, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Assert.fail("Could not get int[] supported formats: " + e.toString()); + } + Assert.assertNotNull(toReturn); + return toReturn; + } + private static BarcodeDetectionResult[] detect(org.chromium.skia.mojom.Bitmap mojoBitmap) { BarcodeDetectorOptions options = new BarcodeDetectorOptions(); BarcodeDetection detector = new BarcodeDetectionImpl(options); @@ -51,6 +79,17 @@ @Test @SmallTest @Feature({"ShapeDetection"}) + public void testEnumerateSupportedFormats() { + if (!TestUtils.IS_GMS_CORE_SUPPORTED) { + return; + } + int[] results = enumerateSupportedFormats(); + Assert.assertArrayEquals(SUPPORTED_FORMATS, results); + } + + @Test + @SmallTest + @Feature({"ShapeDetection"}) public void testDetectBase64ValidImageString() { if (!TestUtils.IS_GMS_CORE_SUPPORTED) { return;
diff --git a/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/services/shape_detection/barcode_detection_impl_mac_unittest.mm index 161510b..340a83d7 100644 --- a/services/shape_detection/barcode_detection_impl_mac_unittest.mm +++ b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -18,6 +18,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "services/shape_detection/barcode_detection_impl_mac_vision.h" +#include "services/shape_detection/barcode_detection_provider_mac.h" #include "services/shape_detection/public/mojom/barcodedetection.mojom.h" #include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h" #include "testing/gmock/include/gmock/gmock.h" @@ -36,8 +37,25 @@ closure.Run(); } -std::unique_ptr<mojom::BarcodeDetection> CreateBarcodeDetectorImplMac( +static const std::vector<mojom::BarcodeFormat>& CISupportedFormats = { + mojom::BarcodeFormat::QR_CODE}; +static const std::vector<mojom::BarcodeFormat>& VisionSupportedFormats = { + mojom::BarcodeFormat::AZTEC, mojom::BarcodeFormat::CODE_128, + mojom::BarcodeFormat::CODE_39, mojom::BarcodeFormat::CODE_93, + mojom::BarcodeFormat::DATA_MATRIX, mojom::BarcodeFormat::EAN_13, + mojom::BarcodeFormat::EAN_8, mojom::BarcodeFormat::ITF, + mojom::BarcodeFormat::PDF417, mojom::BarcodeFormat::QR_CODE, + mojom::BarcodeFormat::UPC_E}; + +std::unique_ptr<mojom::BarcodeDetectionProvider> CreateBarcodeProviderMac() { + return std::make_unique<BarcodeDetectionProviderMac>(); +} + +std::unique_ptr<mojom::BarcodeDetection> CreateBarcodeDetectorImplMacCI( mojom::BarcodeDetectorOptionsPtr options) { + if (@available(macOS 10.13, *)) { + return nullptr; + } if (@available(macOS 10.10, *)) { return std::make_unique<BarcodeDetectionImplMac>(); } @@ -62,10 +80,13 @@ struct TestParams { size_t num_barcodes; const std::string barcode_value; + const std::vector<mojom::BarcodeFormat> formats; BarcodeDetectorFactory factory; } kTestParams[] = { - {1, kInfoString, base::Bind(&CreateBarcodeDetectorImplMac)}, - {1, kInfoString, base::Bind(&CreateBarcodeDetectorImplMacVision)}, + {1, kInfoString, CISupportedFormats, + base::BindRepeating(&CreateBarcodeDetectorImplMacCI)}, + {1, kInfoString, VisionSupportedFormats, + base::BindRepeating(&CreateBarcodeDetectorImplMacVision)}, }; } @@ -78,13 +99,12 @@ vision_framework_ = dlopen( "/System/Library/Frameworks/Vision.framework/Vision", RTLD_LAZY); } + provider_ = base::BindOnce(&CreateBarcodeProviderMac).Run(); } void TearDown() override { - if (@available(macOS 10.13, *)) { - if (vision_framework_) - dlclose(vision_framework_); - } + if (vision_framework_) + dlclose(vision_framework_); } void DetectCallback(size_t num_barcodes, @@ -98,20 +118,49 @@ } MOCK_METHOD0(Detection, void(void)); + void EnumerateSupportedFormatsCallback( + const std::vector<mojom::BarcodeFormat>& expected, + const std::vector<mojom::BarcodeFormat>& results) { + EXPECT_THAT(results, + testing::ElementsAreArray(expected.begin(), expected.end())); + + OnEnumerateSupportedFormats(); + } + MOCK_METHOD0(OnEnumerateSupportedFormats, void(void)); + std::unique_ptr<mojom::BarcodeDetection> impl_; + std::unique_ptr<mojom::BarcodeDetectionProvider> provider_; const base::MessageLoop message_loop_; - void* vision_framework_; + void* vision_framework_ = nullptr; }; TEST_P(BarcodeDetectionImplMacTest, CreateAndDestroy) { impl_ = GetParam().factory.Run(mojom::BarcodeDetectorOptions::New()); if (!impl_) { - LOG(WARNING) << "Barcode Detection is not supported before Mac OSX 10.10." - << "Skipping test."; + LOG(WARNING) << "Barcode Detection for this (library, OS version) pair is " + "not supported, skipping test."; return; } } +TEST_P(BarcodeDetectionImplMacTest, EnumerateSupportedBarcodes) { + impl_ = GetParam().factory.Run(mojom::BarcodeDetectorOptions::New()); + if (!impl_) { + LOG(WARNING) << "Barcode Detection for this (library, OS version) pair is " + "not supported, skipping test."; + return; + } + + base::RunLoop run_loop; + base::RepeatingClosure quit_closure = run_loop.QuitClosure(); + EXPECT_CALL(*this, OnEnumerateSupportedFormats()) + .WillOnce(RunClosure(quit_closure)); + provider_->EnumerateSupportedFormats(base::BindOnce( + &BarcodeDetectionImplMacTest::EnumerateSupportedFormatsCallback, + base::Unretained(this), GetParam().formats)); + run_loop.Run(); +} + // This test generates a single QR code and scans it back. TEST_P(BarcodeDetectionImplMacTest, ScanOneBarcode) { // Barcode detection needs at least MAC OS X 10.10, and GPU infrastructure.
diff --git a/services/tracing/agent_registry.cc b/services/tracing/agent_registry.cc index f1e4764..30e38ae 100644 --- a/services/tracing/agent_registry.cc +++ b/services/tracing/agent_registry.cc
@@ -118,10 +118,11 @@ auto id = next_agent_id_++; auto entry = std::make_unique<AgentEntry>(id, this, std::move(agent), label, type, pid); - if (!agent_initialization_callback_.is_null()) - agent_initialization_callback_.Run(entry.get()); + AgentEntry* entry_ptr = entry.get(); auto result = agents_.insert(std::make_pair(id, std::move(entry))); DCHECK(result.second); + if (!agent_initialization_callback_.is_null()) + agent_initialization_callback_.Run(entry_ptr); } void AgentRegistry::UnregisterAgent(size_t agent_id) {
diff --git a/services/tracing/perfetto/chrome_event_bundle_json_exporter.cc b/services/tracing/perfetto/chrome_event_bundle_json_exporter.cc index 46de552..a4b30e4 100644 --- a/services/tracing/perfetto/chrome_event_bundle_json_exporter.cc +++ b/services/tracing/perfetto/chrome_event_bundle_json_exporter.cc
@@ -151,9 +151,10 @@ } // namespace ChromeEventBundleJsonExporter::ChromeEventBundleJsonExporter( - bool filter_args, + JSONTraceExporter::ArgumentFilterPredicate argument_filter_predicate, JSONTraceExporter::OnTraceEventJSONCallback callback) - : JSONTraceExporter(filter_args, std::move(callback)) {} + : JSONTraceExporter(std::move(argument_filter_predicate), + std::move(callback)) {} void ChromeEventBundleJsonExporter::ProcessPackets( const std::vector<perfetto::TracePacket>& packets) {
diff --git a/services/tracing/perfetto/chrome_event_bundle_json_exporter.h b/services/tracing/perfetto/chrome_event_bundle_json_exporter.h index 08e331d0..db1cc3c 100644 --- a/services/tracing/perfetto/chrome_event_bundle_json_exporter.h +++ b/services/tracing/perfetto/chrome_event_bundle_json_exporter.h
@@ -25,8 +25,9 @@ // Conversion happens on-the-fly as new trace packets are received. class ChromeEventBundleJsonExporter : public JSONTraceExporter { public: - ChromeEventBundleJsonExporter(bool filter_args, - OnTraceEventJSONCallback callback); + ChromeEventBundleJsonExporter( + ArgumentFilterPredicate argument_filter_predicate, + OnTraceEventJSONCallback callback); ~ChromeEventBundleJsonExporter() override = default; protected:
diff --git a/services/tracing/perfetto/chrome_event_bundle_json_exporter_unittest.cc b/services/tracing/perfetto/chrome_event_bundle_json_exporter_unittest.cc index cf30a719..395ee5f 100644 --- a/services/tracing/perfetto/chrome_event_bundle_json_exporter_unittest.cc +++ b/services/tracing/perfetto/chrome_event_bundle_json_exporter_unittest.cc
@@ -31,11 +31,36 @@ namespace tracing { +namespace { + +bool IsArgNameWhitelisted(const char* arg_name) { + return base::MatchPattern(arg_name, "granular_arg_whitelisted"); +} + +bool IsTraceEventArgsWhitelisted( + const char* category_group_name, + const char* event_name, + base::trace_event::ArgumentNameFilterPredicate* arg_filter) { + if (base::MatchPattern(category_group_name, "toplevel") && + base::MatchPattern(event_name, "*")) { + return true; + } + if (base::MatchPattern(category_group_name, "benchmark") && + base::MatchPattern(event_name, "granularly_whitelisted")) { + *arg_filter = base::BindRepeating(&IsArgNameWhitelisted); + return true; + } + + return false; +} + +} // namespace + class ChromeEventBundleJsonExporterTest : public testing::Test { public: void SetUp() override { json_trace_exporter_.reset(new ChromeEventBundleJsonExporter( - /*filter_args=*/false, + JSONTraceExporter::ArgumentFilterPredicate(), base::BindRepeating( &ChromeEventBundleJsonExporterTest::OnTraceEventJSON, base::Unretained(this)))); @@ -44,7 +69,8 @@ void TearDown() override { json_trace_exporter_.reset(); } void EnableArgumentFilter() { - json_trace_exporter_->set_filter_args_for_testing(true); + json_trace_exporter_->SetArgumentFilterForTesting( + base::BindRepeating(&IsTraceEventArgsWhitelisted)); } void OnTraceEventJSON(const std::string& json, @@ -670,13 +696,13 @@ auto* new_trace_event = trace_packet_proto.mutable_chrome_events()->add_trace_events(); SetTestPacketBasicData(new_trace_event); - new_trace_event->set_name("ScopedBlockingCallTest"); - new_trace_event->set_category_group_name("base"); + new_trace_event->set_name("granularly_whitelisted"); + new_trace_event->set_category_group_name("benchmark"); auto* new_arg1 = new_trace_event->add_args(); - new_arg1->set_name("file_name"); + new_arg1->set_name("granular_arg_whitelisted"); new_arg1->set_string_value("whitelisted_value"); auto* new_arg2 = new_trace_event->add_args(); - new_arg2->set_name("file_number"); + new_arg2->set_name("granular_arg_blacklisted"); new_arg2->set_string_value("blacklisted_value"); } @@ -701,12 +727,12 @@ { const auto* trace_event = trace_analyzer()->FindFirstOf( trace_analyzer::Query(trace_analyzer::Query::EVENT_NAME) == - trace_analyzer::Query::String("ScopedBlockingCallTest")); + trace_analyzer::Query::String("granularly_whitelisted")); EXPECT_TRUE(trace_event); EXPECT_EQ("whitelisted_value", - trace_event->GetKnownArgAsString(("file_name"))); + trace_event->GetKnownArgAsString(("granular_arg_whitelisted"))); EXPECT_EQ("__stripped__", - trace_event->GetKnownArgAsString(("file_number"))); + trace_event->GetKnownArgAsString(("granular_arg_blacklisted"))); } }
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc index 6cda65b..6e6b4af7 100644 --- a/services/tracing/perfetto/json_trace_exporter.cc +++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -11,7 +11,6 @@ #include "base/json/json_writer.h" #include "base/json/string_escape.h" #include "base/trace_event/trace_event.h" -#include "services/tracing/public/cpp/trace_event_args_whitelist.h" #include "third_party/perfetto/include/perfetto/tracing/core/trace_packet.h" #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h" #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_packet.pb.h" @@ -24,11 +23,12 @@ } // namespace -JSONTraceExporter::JSONTraceExporter(bool filter_args, - OnTraceEventJSONCallback callback) +JSONTraceExporter::JSONTraceExporter( + ArgumentFilterPredicate argument_filter_predicate, + OnTraceEventJSONCallback callback) : out_(callback), metadata_(std::make_unique<base::DictionaryValue>()), - filter_args_(filter_args) {} + argument_filter_predicate_(std::move(argument_filter_predicate)) {} JSONTraceExporter::~JSONTraceExporter() = default; @@ -194,8 +194,8 @@ int32_t tid) { DCHECK(ShouldOutputTraceEvents()); return JSONTraceExporter::ScopedJSONTraceEventAppender( - AddJSONTraceEvent(), filter_args_, name, categories, phase, timestamp, - pid, tid); + AddJSONTraceEvent(), argument_filter_predicate_, name, categories, phase, + timestamp, pid, tid); } JSONTraceExporter::StringBuffer* JSONTraceExporter::AddJSONTraceEvent() { @@ -279,14 +279,16 @@ } JSONTraceExporter::ArgumentBuilder::ArgumentBuilder( - bool filter_args, + const ArgumentFilterPredicate& argument_filter_predicate, const char* name, const char* category_group_name, StringBuffer* out) : out_(out) { - strip_args_ = filter_args && - !IsTraceEventArgsWhitelisted(category_group_name, name, - &argument_name_filter_predicate_); + JSONTraceExporter::ArgumentNameFilterPredicate argument_name_filter_predicate; + strip_args_ = + !argument_filter_predicate.is_null() && + !argument_filter_predicate.Run(category_group_name, name, + &argument_name_filter_predicate_); *out_ += ",\"args\":"; } @@ -341,7 +343,7 @@ JSONTraceExporter::ScopedJSONTraceEventAppender::ScopedJSONTraceEventAppender( JSONTraceExporter::StringBuffer* out, - bool filter_args, + JSONTraceExporter::ArgumentFilterPredicate argument_filter_predicate, const char* name, const char* categories, int32_t phase, @@ -353,7 +355,7 @@ out_(out), event_name_(name), category_group_name_(categories), - filter_args_(filter_args) { + argument_filter_predicate_(std::move(argument_filter_predicate)) { out_->AppendF("{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"cat\":\"%s\",\"name\":", pid, tid, timestamp, phase_, categories); @@ -364,7 +366,7 @@ JSONTraceExporter::ScopedJSONTraceEventAppender&& move) { out_ = move.out_; phase_ = move.phase_; - filter_args_ = move.filter_args_; + argument_filter_predicate_ = std::move(move.argument_filter_predicate_); // We null out the string so that the destructor knows not to append the // closing brace for the json. move.out_ = nullptr; @@ -475,7 +477,7 @@ JSONTraceExporter::ScopedJSONTraceEventAppender::BuildArgs() { DCHECK(!added_args_); added_args_ = true; - return std::make_unique<ArgumentBuilder>(filter_args_, event_name_, - category_group_name_, out_); + return std::make_unique<ArgumentBuilder>( + argument_filter_predicate_, event_name_, category_group_name_, out_); } } // namespace tracing
diff --git a/services/tracing/perfetto/json_trace_exporter.h b/services/tracing/perfetto/json_trace_exporter.h index 4aae8e0..2b1878b 100644 --- a/services/tracing/perfetto/json_trace_exporter.h +++ b/services/tracing/perfetto/json_trace_exporter.h
@@ -36,19 +36,29 @@ using ArgumentNameFilterPredicate = base::RepeatingCallback<bool(const char* arg_name)>; + // Given trace event name and category group name, returns a argument name + // filter predicate callback that can filter arguments for the given event. + using ArgumentFilterPredicate = + base::RepeatingCallback<bool(const char* category_group_name, + const char* event_name, + ArgumentNameFilterPredicate*)>; + using OnTraceEventJSONCallback = base::RepeatingCallback<void(const std::string& json, base::DictionaryValue* metadata, bool has_more)>; - JSONTraceExporter(bool filter_args, OnTraceEventJSONCallback callback); + JSONTraceExporter(ArgumentFilterPredicate argument_filter_predicate, + OnTraceEventJSONCallback callback); virtual ~JSONTraceExporter(); // Called to notify the exporter of new trace packets. Will call the // |json_callback| passed in the constructor with the converted trace data. void OnTraceData(std::vector<perfetto::TracePacket> packets, bool has_more); - void set_filter_args_for_testing(bool value) { filter_args_ = value; } + void SetArgumentFilterForTesting(const ArgumentFilterPredicate& predicate) { + argument_filter_predicate_ = predicate; + } void set_label_filter(const std::string& label_filter) { label_filter_ = label_filter; @@ -92,7 +102,7 @@ class ArgumentBuilder { public: - ArgumentBuilder(bool filter_args, + ArgumentBuilder(const ArgumentFilterPredicate& argument_filter_predicate, const char* name, const char* category_group_name, StringBuffer* out); @@ -172,14 +182,15 @@ private: // Subclasses of JSONTraceExporter can create a new instance by calling // AddTraceEvent(). - ScopedJSONTraceEventAppender(StringBuffer* out, - bool filter_args, - const char* name, - const char* categories, - int32_t phase, - int64_t timestamp, - int32_t pid, - int32_t tid); + ScopedJSONTraceEventAppender( + StringBuffer* out, + ArgumentFilterPredicate argument_filter_predicate, + const char* name, + const char* categories, + int32_t phase, + int64_t timestamp, + int32_t pid, + int32_t tid); friend class JSONTraceExporter; char phase_; @@ -187,7 +198,7 @@ StringBuffer* out_; const char* event_name_; const char* category_group_name_; - bool filter_args_; + ArgumentFilterPredicate argument_filter_predicate_; }; // Subclasses implement this to add data from |packets| to the JSON output. @@ -237,7 +248,7 @@ std::string label_filter_; std::string legacy_system_ftrace_output_; std::unique_ptr<base::DictionaryValue> metadata_; - bool filter_args_; + ArgumentFilterPredicate argument_filter_predicate_; DISALLOW_COPY_AND_ASSIGN(JSONTraceExporter); };
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc index 983a251..da512a135 100644 --- a/services/tracing/perfetto/json_trace_exporter_unittest.cc +++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -84,8 +84,10 @@ class TestJSONTraceExporter : public JSONTraceExporter { public: - TestJSONTraceExporter(bool filter_args, OnTraceEventJSONCallback callback) - : JSONTraceExporter(filter_args, std::move(callback)) {} + TestJSONTraceExporter(ArgumentFilterPredicate argument_filter_predicate, + OnTraceEventJSONCallback callback) + : JSONTraceExporter(std::move(argument_filter_predicate), + std::move(callback)) {} ~TestJSONTraceExporter() override = default; int process_packets_calls() const { return process_packets_calls_; } @@ -186,7 +188,7 @@ public: JsonTraceExporterTest() : json_trace_exporter_(new TestJSONTraceExporter( - /* filter_args =*/false, + JSONTraceExporter::ArgumentFilterPredicate(), base::BindRepeating(&JsonTraceExporterTest::OnTraceEventJSON, base::Unretained(this)))) {} @@ -440,53 +442,70 @@ TEST_F(JsonTraceExporterTest, TestAddArgsArgumentStripping) { std::vector<FakeTraceInfo> infos = { - FakeTraceInfo("event1", "base", 'B', /* timestamp = */ 1, + FakeTraceInfo("event1", "toplevel", 'B', /* timestamp = */ 1, /* pid = */ 2, /* tid = */ 3), - FakeTraceInfo("whitewashed", "base", 'B', /* timestamp = */ 1, + FakeTraceInfo("event2", "whitewashed", 'B', /* timestamp = */ 1, /* pid = */ 2, /* tid = */ 3), - FakeTraceInfo("ScopedBlockingCallTest", "base", 'B', + FakeTraceInfo("event3", "granular_whitelisted", 'B', /* timestamp = */ 1, /* pid = */ 2, /* tid = */ 3)}; infos[0].args.emplace_back("int_one", int64_t(1)); infos[1].args.emplace_back("int_two", uint64_t(2)); // Third arg only has index into the string table. - infos[2].args.emplace_back("file_name", std::string("\"whitelisted_value\"")); - infos[2].args.emplace_back("file_number", + infos[2].args.emplace_back("granular_arg_whitelisted", + std::string("\"whitelisted_value\"")); + infos[2].args.emplace_back("granular_arg_blacklisted", std::string("\"blacklisted_value\"")); - json_trace_exporter_->set_filter_args_for_testing(true); + json_trace_exporter_->SetArgumentFilterForTesting(base::BindRepeating( + [](const char* category_group_name, const char* event_name, + base::trace_event::ArgumentNameFilterPredicate* arg_filter) { + if (base::MatchPattern(category_group_name, "toplevel") && + base::MatchPattern(event_name, "*")) { + return true; + } + if (base::MatchPattern(category_group_name, "granular_whitelisted") && + base::MatchPattern(event_name, "event3")) { + *arg_filter = base::BindRepeating([](const char* arg_name) { + return base::MatchPattern(arg_name, "granular_arg_whitelisted"); + }); + return true; + } + return false; + })); json_trace_exporter_->SetFakeTraceEvents(infos); json_trace_exporter_->OnTraceData( std::vector<perfetto::TracePacket>(infos.size()), false); EXPECT_EQ( "{\"traceEvents\":[{\"pid\":2,\"tid\":3,\"ts\":1,\"ph\":\"B\"," - "\"cat\":\"base\",\"name\":\"event1\",\"args\":\"__stripped__\"},\n" - "{\"pid\":2,\"tid\":3,\"ts\":1,\"ph\":\"B\",\"cat\":\"base\"," - "\"name\":\"whitewashed\",\"args\":\"__stripped__\"},\n" + "\"cat\":\"toplevel\",\"name\":\"event1\",\"args\":{\"int_one\":1}},\n" + "{\"pid\":2,\"tid\":3,\"ts\":1,\"ph\":\"B\",\"cat\":\"whitewashed\"," + "\"name\":\"event2\",\"args\":\"__stripped__\"},\n" "{\"pid\":2,\"tid\":3,\"ts\":1,\"ph\":\"B\"," - "\"cat\":\"base\",\"name\":\"ScopedBlockingCallTest\"," - "\"args\":{\"file_name\":\"whitelisted_value\"," - "\"file_number\":\"__stripped__\"}}]}", + "\"cat\":\"granular_whitelisted\",\"name\":\"event3\"," + "\"args\":{\"granular_arg_whitelisted\":\"whitelisted_value\"," + "\"granular_arg_blacklisted\":\"__stripped__\"}}]}", unparsed_trace_data_); const trace_analyzer::TraceEvent* trace_event = trace_analyzer_->FindFirstOf( trace_analyzer::Query(trace_analyzer::Query::EVENT_NAME) == trace_analyzer::Query::String("event1")); - EXPECT_FALSE(trace_event->HasArg("int_one")); EXPECT_TRUE(trace_event); + EXPECT_EQ(1, trace_event->GetKnownArgAsDouble("int_one")); trace_event = trace_analyzer_->FindFirstOf( trace_analyzer::Query(trace_analyzer::Query::EVENT_NAME) == - trace_analyzer::Query::String("whitewashed")); + trace_analyzer::Query::String("event2")); EXPECT_FALSE(trace_event->HasArg("int_two")); trace_event = trace_analyzer_->FindFirstOf( trace_analyzer::Query(trace_analyzer::Query::EVENT_NAME) == - trace_analyzer::Query::String("ScopedBlockingCallTest")); + trace_analyzer::Query::String("event3")); EXPECT_EQ("whitelisted_value", - trace_event->GetKnownArgAsString(("file_name"))); - EXPECT_EQ("__stripped__", trace_event->GetKnownArgAsString(("file_number"))); + trace_event->GetKnownArgAsString(("granular_arg_whitelisted"))); + EXPECT_EQ("__stripped__", + trace_event->GetKnownArgAsString(("granular_arg_blacklisted"))); } TEST_F(JsonTraceExporterTest, TestFtraceLegacyOutput) {
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.cc b/services/tracing/perfetto/perfetto_tracing_coordinator.cc index e4f43527..20156e4 100644 --- a/services/tracing/perfetto/perfetto_tracing_coordinator.cc +++ b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
@@ -11,10 +11,12 @@ #include "base/bind.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" +#include "base/trace_event/trace_log.h" #include "build/build_config.h" #include "mojo/public/cpp/system/data_pipe_utils.h" #include "services/tracing/perfetto/chrome_event_bundle_json_exporter.h" #include "services/tracing/perfetto/perfetto_service.h" +#include "services/tracing/public/cpp/trace_event_args_whitelist.h" #include "services/tracing/public/mojom/constants.mojom.h" #include "services/tracing/public/mojom/perfetto_service.mojom.h" #include "third_party/perfetto/include/perfetto/tracing/core/consumer.h" @@ -32,12 +34,27 @@ // vs. proto). class PerfettoTracingCoordinator::TracingSession : public perfetto::Consumer { public: - TracingSession(const std::string& config, + TracingSession(const base::trace_event::TraceConfig& chrome_config, base::OnceClosure tracing_over_callback) : tracing_over_callback_(std::move(tracing_over_callback)) { - base::trace_event::TraceConfig chrome_trace_config_obj(config); + // In legacy backend, the trace event agent sets the predicate used by + // TraceLog. For perfetto backend, ensure that predicate is always set + // before creating the exporter. The agent can be created later than this + // point. + if (base::trace_event::TraceLog::GetInstance() + ->GetArgumentFilterPredicate() + .is_null()) { + base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate( + base::BindRepeating(&IsTraceEventArgsWhitelisted)); + base::trace_event::TraceLog::GetInstance()->SetMetadataFilterPredicate( + base::BindRepeating(&IsMetadataWhitelisted)); + } + json_trace_exporter_ = std::make_unique<ChromeEventBundleJsonExporter>( - chrome_trace_config_obj.IsArgumentFilterEnabled(), + chrome_config.IsArgumentFilterEnabled() + ? base::trace_event::TraceLog::GetInstance() + ->GetArgumentFilterPredicate() + : JSONTraceExporter::ArgumentFilterPredicate(), base::BindRepeating(&TracingSession::OnJSONTraceEventCallback, base::Unretained(this))); perfetto::TracingService* service = @@ -45,55 +62,8 @@ consumer_endpoint_ = service->ConnectConsumer(this, /*uid=*/0); // Start tracing. - perfetto::TraceConfig trace_config; - size_t size_limit = chrome_trace_config_obj.GetTraceBufferSizeInKb(); - if (size_limit == 0) { - size_limit = 100 * 1024; - } - trace_config.add_buffers()->set_size_kb(size_limit); - - // Perfetto uses clock_gettime for its internal snapshotting, which gets - // blocked by the sandboxed and isn't needed for Chrome regardless. - trace_config.set_disable_clock_snapshotting(true); - - auto* trace_event_data_source = trace_config.add_data_sources(); - for (auto& enabled_pid : chrome_trace_config_obj.process_filter_config() - .included_process_ids()) { - *trace_event_data_source->add_producer_name_filter() = - base::StrCat({mojom::kPerfettoProducerName, ".", - base::NumberToString(enabled_pid)}); - } - - auto* trace_event_config = trace_event_data_source->mutable_config(); - trace_event_config->set_name(mojom::kTraceEventDataSourceName); - trace_event_config->set_target_buffer(0); - auto* chrome_config = trace_event_config->mutable_chrome_config(); - chrome_config->set_trace_config(config); - -// Only CrOS and Cast support system tracing. -#if defined(OS_CHROMEOS) || (defined(IS_CHROMECAST) && defined(OS_LINUX)) - auto* system_trace_config = - trace_config.add_data_sources()->mutable_config(); - system_trace_config->set_name(mojom::kSystemTraceDataSourceName); - system_trace_config->set_target_buffer(0); - auto* system_chrome_config = system_trace_config->mutable_chrome_config(); - system_chrome_config->set_trace_config(config); -#endif - -#if defined(OS_CHROMEOS) - auto* arc_trace_config = trace_config.add_data_sources()->mutable_config(); - arc_trace_config->set_name(mojom::kArcTraceDataSourceName); - arc_trace_config->set_target_buffer(0); - auto* arc_chrome_config = arc_trace_config->mutable_chrome_config(); - arc_chrome_config->set_trace_config(config); -#endif - - auto* trace_metadata_config = - trace_config.add_data_sources()->mutable_config(); - trace_metadata_config->set_name(mojom::kMetaDataSourceName); - trace_metadata_config->set_target_buffer(0); - - consumer_endpoint_->EnableTracing(trace_config); + auto perfetto_config = CreatePerfettoConfiguration(chrome_config); + consumer_endpoint_->EnableTracing(perfetto_config); } ~TracingSession() override { @@ -105,6 +75,86 @@ stream_.reset(); } + void ChangeTraceConfig(const base::trace_event::TraceConfig& chrome_config) { + auto perfetto_config = CreatePerfettoConfiguration(chrome_config); + consumer_endpoint_->ChangeTraceConfig(perfetto_config); + } + + perfetto::TraceConfig CreatePerfettoConfiguration( + const base::trace_event::TraceConfig& chrome_config) { + perfetto::TraceConfig perfetto_config; + size_t size_limit = chrome_config.GetTraceBufferSizeInKb(); + if (size_limit == 0) { + size_limit = 100 * 1024; + } + perfetto_config.add_buffers()->set_size_kb(size_limit); + + // Perfetto uses clock_gettime for its internal snapshotting, which gets + // blocked by the sandboxed and isn't needed for Chrome regardless. + perfetto_config.set_disable_clock_snapshotting(true); + + auto* trace_event_data_source = perfetto_config.add_data_sources(); + for (auto& enabled_pid : + chrome_config.process_filter_config().included_process_ids()) { + *trace_event_data_source->add_producer_name_filter() = + base::StrCat({mojom::kPerfettoProducerName, ".", + base::NumberToString(enabled_pid)}); + } + + // We strip the process filter from the config string we send to Perfetto, + // so perfetto doesn't reject it from a future + // TracingService::ChangeTraceConfig call due to being an unsupported + // update. + base::trace_event::TraceConfig processfilter_stripped_config(chrome_config); + processfilter_stripped_config.SetProcessFilterConfig( + base::trace_event::TraceConfig::ProcessFilterConfig()); + +#if DCHECK_IS_ON() + // Ensure that the process filter is the only thing that gets changed + // in a configuration during a tracing session. + DCHECK((last_config_for_perfetto_.ToString() == + base::trace_event::TraceConfig().ToString()) || + (last_config_for_perfetto_.ToString() == + processfilter_stripped_config.ToString())); + last_config_for_perfetto_ = processfilter_stripped_config; +#endif + + auto* trace_event_config = trace_event_data_source->mutable_config(); + trace_event_config->set_name(mojom::kTraceEventDataSourceName); + trace_event_config->set_target_buffer(0); + auto* chrome_proto_config = trace_event_config->mutable_chrome_config(); + chrome_proto_config->set_trace_config( + processfilter_stripped_config.ToString()); + +// Only CrOS and Cast support system tracing. +#if defined(OS_CHROMEOS) || (defined(IS_CHROMECAST) && defined(OS_LINUX)) + auto* system_trace_config = + perfetto_config.add_data_sources()->mutable_config(); + system_trace_config->set_name(mojom::kSystemTraceDataSourceName); + system_trace_config->set_target_buffer(0); + auto* system_chrome_config = system_trace_config->mutable_chrome_config(); + system_chrome_config->set_trace_config( + processfilter_stripped_config.ToString()); +#endif + +#if defined(OS_CHROMEOS) + auto* arc_trace_config = + perfetto_config.add_data_sources()->mutable_config(); + arc_trace_config->set_name(mojom::kArcTraceDataSourceName); + arc_trace_config->set_target_buffer(0); + auto* arc_chrome_config = arc_trace_config->mutable_chrome_config(); + arc_chrome_config->set_trace_config( + processfilter_stripped_config.ToString()); +#endif + + auto* trace_metadata_config = + perfetto_config.add_data_sources()->mutable_config(); + trace_metadata_config->set_name(mojom::kMetaDataSourceName); + trace_metadata_config->set_target_buffer(0); + + return perfetto_config; + } + void StopAndFlush(mojo::ScopedDataPipeProducerHandle stream, const std::string& agent_label, StopAndFlushCallback callback) { @@ -191,6 +241,10 @@ base::OnceClosure tracing_over_callback_; RequestBufferUsageCallback request_buffer_usage_callback_; +#if DCHECK_IS_ON() + base::trace_event::TraceConfig last_config_for_perfetto_; +#endif + // Keep last to avoid edge-cases where its callbacks come in mid-destruction. std::unique_ptr<perfetto::TracingService::ConsumerEndpoint> consumer_endpoint_; @@ -231,9 +285,14 @@ StartTracingCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); parsed_config_ = base::trace_event::TraceConfig(config); - tracing_session_ = std::make_unique<TracingSession>( - config, base::BindOnce(&PerfettoTracingCoordinator::OnTracingOverCallback, - weak_factory_.GetWeakPtr())); + if (!tracing_session_) { + tracing_session_ = std::make_unique<TracingSession>( + parsed_config_, + base::BindOnce(&PerfettoTracingCoordinator::OnTracingOverCallback, + weak_factory_.GetWeakPtr())); + } else { + tracing_session_->ChangeTraceConfig(parsed_config_); + } agent_registry_->SetAgentInitializationCallback( base::BindRepeating(&PerfettoTracingCoordinator::PingAgent,
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom index a49223c3..9b9e0df 100644 --- a/services/ws/public/mojom/window_manager.mojom +++ b/services/ws/public/mojom/window_manager.mojom
@@ -63,8 +63,11 @@ // A boolean determining whether animations are disabled for the window. const string kAnimationsDisabled_Property = "prop:animations-disabled"; - // The application icon; typically larger for shelf icons, etc. Type: SkBitmap - const string kAppIcon_Property = "prop:app-icon"; + // A large version of the application icon. Type: SkBitmap + const string kAppIconLarge_Property = "prop:app-icon-large"; + + // A small version of the application icon. Type: SkBitmap + const string kAppIconSmall_Property = "prop:app-icon-small"; // The Android Java-style package name for an ARC++ window, such as // "com.google.Photos". Type: mojom::String. @@ -153,9 +156,6 @@ // aura::client::kWindowCornerRadiusKey. Type: int. const string kWindowCornerRadius_Property = "prop:window-corner-radius"; - // The window icon; typically 16x16 for titlebars. Type: SkBitmap - const string kWindowIcon_Property = "prop:window-icon"; - // The window's title. Maps to aura::client::kTitleKey. Type: mojom::String const string kWindowTitle_Property = "prop:window-title";
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 49d9ade..80bbbf44 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -87,25 +87,6 @@ return type == StorageType::kTemporary || type == StorageType::kPersistent; } -void CountOriginType(const std::set<url::Origin>& origins, - SpecialStoragePolicy* policy, - size_t* protected_origins, - size_t* unlimited_origins) { - DCHECK(protected_origins); - DCHECK(unlimited_origins); - *protected_origins = 0; - *unlimited_origins = 0; - if (!policy) - return; - for (const auto& origin : origins) { - const GURL url = origin.GetURL(); - if (policy->IsStorageProtected(url)) - ++*protected_origins; - if (policy->IsStorageUnlimited(url)) - ++*unlimited_origins; - } -} - bool GetPersistentHostQuotaOnDBThread(const std::string& host, int64_t* quota, QuotaDatabase* database) { @@ -1495,22 +1476,6 @@ UMA_HISTOGRAM_PERCENTAGE("Quota.PercentUsedForTemporaryStorage2", static_cast<int>((usage * 100) / total_space)); - std::set<url::Origin> origins; - GetCachedOrigins(StorageType::kTemporary, &origins); - - size_t num_origins = origins.size(); - size_t protected_origins = 0; - size_t unlimited_origins = 0; - CountOriginType(origins, - special_storage_policy_.get(), - &protected_origins, - &unlimited_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfTemporaryStorageOrigins", num_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfProtectedTemporaryStorageOrigins", - protected_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfUnlimitedTemporaryStorageOrigins", - unlimited_origins); - GetGlobalUsage( StorageType::kPersistent, base::BindOnce(&QuotaManager::DidGetPersistentGlobalUsageForHistogram, @@ -1523,23 +1488,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage); - std::set<url::Origin> origins; - GetCachedOrigins(StorageType::kPersistent, &origins); - - size_t num_origins = origins.size(); - size_t protected_origins = 0; - size_t unlimited_origins = 0; - CountOriginType(origins, - special_storage_policy_.get(), - &protected_origins, - &unlimited_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfPersistentStorageOrigins", - num_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfProtectedPersistentStorageOrigins", - protected_origins); - UMA_HISTOGRAM_COUNTS_1M("Quota.NumberOfUnlimitedPersistentStorageOrigins", - unlimited_origins); - // We DumpOriginInfoTable last to ensure the trackers caches are loaded. DumpOriginInfoTable( base::BindOnce(&QuotaManager::DidDumpOriginInfoTableForHistogram,
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.cc b/storage/browser/quota/quota_temporary_storage_evictor.cc index 92253025..1aca6fe8 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.cc +++ b/storage/browser/quota/quota_temporary_storage_evictor.cc
@@ -34,7 +34,6 @@ QuotaTemporaryStorageEvictor::EvictionRoundStatistics::EvictionRoundStatistics() : in_round(false), is_initialized(false), - usage_overage_at_round(-1), diskspace_shortage_at_round(-1), usage_on_beginning_of_round(-1), usage_on_end_of_round(-1), @@ -83,8 +82,6 @@ if (!time_of_end_of_last_round_.is_null()) UMA_HISTOGRAM_MINUTES("Quota.TimeDeltaOfEvictionRounds", now - time_of_end_of_last_round_); - UMA_HISTOGRAM_MBYTES("Quota.UsageOverageOfTemporaryGlobalStorage", - round_statistics_.usage_overage_at_round); UMA_HISTOGRAM_MBYTES("Quota.DiskspaceShortage", round_statistics_.diskspace_shortage_at_round); UMA_HISTOGRAM_MBYTES("Quota.EvictedBytesPerRound", @@ -100,10 +97,6 @@ stats_in_hour.subtract_assign(previous_statistics_); previous_statistics_ = statistics_; - UMA_HISTOGRAM_COUNTS_1M("Quota.ErrorsOnEvictingOriginPerHour", - stats_in_hour.num_errors_on_evicting_origin); - UMA_HISTOGRAM_COUNTS_1M("Quota.ErrorsOnGettingUsageAndQuotaPerHour", - stats_in_hour.num_errors_on_getting_usage_and_quota); UMA_HISTOGRAM_COUNTS_1M("Quota.EvictedOriginsPerHour", stats_in_hour.num_evicted_origins); UMA_HISTOGRAM_COUNTS_1M("Quota.EvictionRoundsPerHour", @@ -199,7 +192,6 @@ } if (!round_statistics_.is_initialized) { - round_statistics_.usage_overage_at_round = usage_overage; round_statistics_.diskspace_shortage_at_round = diskspace_shortage; round_statistics_.usage_on_beginning_of_round = current_usage; round_statistics_.is_initialized = true;
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h index 4cfecb2c..73aa55c6 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.h +++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -64,7 +64,6 @@ bool is_initialized; base::Time start_time; - int64_t usage_overage_at_round; int64_t diskspace_shortage_at_round; int64_t usage_on_beginning_of_round;
diff --git a/testing/BUILD.gn b/testing/BUILD.gn index 34cf492f..a5ccdd3 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn
@@ -32,6 +32,7 @@ "//testing/scripts/common.py", "//testing/scripts/run_performance_tests.py", "//tools/perf/generate_legacy_perf_dashboard_json.py", + "//tools/perf/core/results_merger.py", ] data_deps = [
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index 0f3b55d..8e3a348 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -563,6 +563,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -574,6 +575,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -585,6 +587,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -596,6 +599,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -607,6 +611,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -618,6 +623,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -629,6 +635,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -640,6 +647,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -651,6 +659,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -663,6 +672,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -674,6 +684,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -685,6 +696,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -696,6 +708,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ], @@ -713,6 +726,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ], @@ -725,6 +739,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -739,6 +754,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -750,6 +766,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -761,6 +778,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -772,6 +790,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -783,6 +802,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -794,6 +814,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -805,6 +826,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -816,6 +838,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -827,6 +850,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -838,6 +862,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -849,6 +874,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -860,6 +886,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ], @@ -877,6 +904,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -888,6 +916,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -899,6 +928,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -910,6 +940,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -921,6 +952,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -932,6 +964,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -943,6 +976,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -954,6 +988,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -965,6 +1000,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -976,6 +1012,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -987,6 +1024,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -998,6 +1036,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1009,6 +1048,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1020,6 +1060,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1031,6 +1072,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1042,6 +1084,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1053,6 +1096,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1064,6 +1108,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1075,6 +1120,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1086,6 +1132,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1097,6 +1144,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1108,6 +1156,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1119,6 +1168,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1130,6 +1180,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -1142,6 +1193,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ], @@ -1159,6 +1211,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1170,6 +1223,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1181,6 +1235,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1192,6 +1247,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1203,6 +1259,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1214,6 +1271,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1225,6 +1283,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1236,6 +1295,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1247,6 +1307,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1258,6 +1319,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1269,6 +1331,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1280,6 +1343,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1291,6 +1355,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1302,6 +1367,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1313,6 +1379,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1324,6 +1391,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1335,6 +1403,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1346,6 +1415,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1357,6 +1427,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1368,6 +1439,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1379,6 +1451,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1390,6 +1463,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -1402,6 +1476,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1413,6 +1488,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1424,6 +1500,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1435,6 +1512,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1446,6 +1524,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -1458,6 +1537,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1469,6 +1549,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1480,6 +1561,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1491,6 +1573,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1502,6 +1585,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1513,6 +1597,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1524,6 +1609,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1535,6 +1621,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1546,6 +1633,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1557,6 +1645,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1568,6 +1657,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1579,6 +1669,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1590,6 +1681,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1601,6 +1693,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1612,6 +1705,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1623,6 +1717,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1634,6 +1729,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1645,6 +1741,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1660,6 +1757,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1671,6 +1769,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1682,6 +1781,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1693,6 +1793,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1704,6 +1805,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1715,6 +1817,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1726,6 +1829,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1737,6 +1841,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1748,6 +1853,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1760,6 +1866,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1771,6 +1878,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1782,6 +1890,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1793,6 +1902,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1807,6 +1917,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1818,6 +1929,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1829,6 +1941,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1840,6 +1953,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1851,6 +1965,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1862,6 +1977,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1873,6 +1989,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1884,6 +2001,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1895,6 +2013,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1906,6 +2025,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1917,6 +2037,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1933,6 +2054,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1944,6 +2066,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1955,6 +2078,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1966,6 +2090,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1977,6 +2102,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1988,6 +2114,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -1999,6 +2126,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2010,6 +2138,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2021,6 +2150,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2032,6 +2162,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2043,6 +2174,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2054,6 +2186,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2065,6 +2198,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2076,6 +2210,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2087,6 +2222,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2098,6 +2234,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2109,6 +2246,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2120,6 +2258,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2131,6 +2270,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2142,6 +2282,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2153,6 +2294,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2164,6 +2306,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -2181,6 +2324,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2192,6 +2336,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2203,6 +2348,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2214,6 +2360,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2225,6 +2372,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2236,6 +2384,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2247,6 +2396,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2258,6 +2408,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2269,6 +2420,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2280,6 +2432,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2291,6 +2444,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2302,6 +2456,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2313,6 +2468,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2324,6 +2480,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2335,6 +2492,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2346,6 +2504,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2357,6 +2516,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2368,6 +2528,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2379,6 +2540,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2390,6 +2552,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2401,6 +2564,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2412,6 +2576,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -2424,6 +2589,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2435,6 +2601,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2446,6 +2613,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2457,6 +2625,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2468,6 +2637,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "integrity": "high", "os": "Windows-10-15063" } @@ -2480,6 +2650,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2491,6 +2662,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2502,6 +2674,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2513,6 +2686,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2524,6 +2698,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2535,6 +2710,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2546,6 +2722,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2557,6 +2734,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2568,6 +2746,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2579,6 +2758,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2590,6 +2770,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2601,6 +2782,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2612,6 +2794,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2623,6 +2806,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2634,6 +2818,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2645,6 +2830,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -2656,6 +2842,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": "x86-64", "os": "Windows-10-15063" } ] @@ -15245,80 +15432,158 @@ "gtest_tests": [ { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "accessibility_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "angle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "app_shell_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "aura_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_fuzzer_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_heap_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_platform_unittests" }, { "name": "webkit_unit_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_crypto_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_ssl_tests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 10 }, "test": "browser_tests" @@ -15331,13 +15596,25 @@ "name": "webui_polymer1_browser_tests", "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 4 }, "test": "browser_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cacheinvalidation_unittests" }, @@ -15346,73 +15623,145 @@ "--gtest_filter=-*UsingRealWebcam*" ], "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "capture_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cast_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cc_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_app_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_cleaner_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_import_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chromedriver_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "compositor_unittests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 6 }, "test": "content_browsertests" @@ -15424,139 +15773,277 @@ ], "name": "perfetto_content_browsertests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "courgette_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crashpad_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crypto_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "device_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "display_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "elevation_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "events_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "filesystem_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcm_unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gfx_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gin_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "google_apis_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gpu_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "install_static_unittests" }, @@ -15565,7 +16052,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -15574,6 +16063,12 @@ { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 3 }, "test": "interactive_ui_tests" @@ -15585,121 +16080,241 @@ ], "name": "webui_polymer1_interactive_ui_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "interactive_ui_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ipc_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "jingle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "latency_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "leveldb_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "libjingle_xmpp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "message_center_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "midi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_core_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "nacl_loader_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "native_theme_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "net_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "pdf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ppapi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "printing_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "remoting_unittests" }, @@ -15708,7 +16323,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -15716,25 +16333,49 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_validation_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "service_manager_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "services_unittests" }, @@ -15743,7 +16384,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -15751,109 +16394,217 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "shell_dialogs_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "skia_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "snapshot_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sql_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "storage_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sync_integration_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "traffic_annotation_auditor_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_touch_selection_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "url_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "views_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "viz_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_pixeltests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wm_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wtf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "zucchini_unittests" } @@ -15863,80 +16614,158 @@ "gtest_tests": [ { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "accessibility_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "angle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "app_shell_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "aura_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_fuzzer_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_heap_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_platform_unittests" }, { "name": "webkit_unit_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_crypto_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_ssl_tests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 20 }, "test": "browser_tests" @@ -15949,13 +16778,25 @@ "name": "webui_polymer1_browser_tests", "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 4 }, "test": "browser_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cacheinvalidation_unittests" }, @@ -15964,73 +16805,145 @@ "--gtest_filter=-*UsingRealWebcam*" ], "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "capture_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cast_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cc_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_app_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_cleaner_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_import_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chromedriver_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "compositor_unittests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 6 }, "test": "content_browsertests" @@ -16042,139 +16955,277 @@ ], "name": "perfetto_content_browsertests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "courgette_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crashpad_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crypto_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "device_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "display_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "elevation_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "events_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "filesystem_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcm_unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gfx_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gin_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "google_apis_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gpu_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "install_static_unittests" }, @@ -16183,7 +17234,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16192,6 +17245,12 @@ { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 3 }, "test": "interactive_ui_tests" @@ -16203,121 +17262,241 @@ ], "name": "webui_polymer1_interactive_ui_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "interactive_ui_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ipc_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "jingle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "latency_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "leveldb_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "libjingle_xmpp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "message_center_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "midi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_core_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "nacl_loader_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "native_theme_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "net_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "pdf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ppapi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "printing_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "remoting_unittests" }, @@ -16326,7 +17505,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16334,25 +17515,49 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_validation_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "service_manager_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "services_unittests" }, @@ -16361,7 +17566,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16369,109 +17576,217 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "shell_dialogs_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "skia_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "snapshot_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sql_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "storage_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sync_integration_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "traffic_annotation_auditor_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_touch_selection_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "url_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "views_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "viz_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_pixeltests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wm_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wtf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "zucchini_unittests" } @@ -16481,80 +17796,158 @@ "gtest_tests": [ { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "accessibility_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "angle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "app_shell_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "aura_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_fuzzer_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_heap_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_platform_unittests" }, { "name": "webkit_unit_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_crypto_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "boringssl_ssl_tests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 10 }, "test": "browser_tests" @@ -16567,13 +17960,25 @@ "name": "webui_polymer1_browser_tests", "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 4 }, "test": "browser_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cacheinvalidation_unittests" }, @@ -16582,73 +17987,145 @@ "--gtest_filter=-*UsingRealWebcam*" ], "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "capture_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cast_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cc_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_app_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_cleaner_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_import_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chrome_elf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "chromedriver_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "components_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "compositor_unittests" }, { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 6 }, "test": "content_browsertests" @@ -16660,139 +18137,277 @@ ], "name": "perfetto_content_browsertests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "content_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "courgette_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crashpad_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "cronet_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "crypto_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "device_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "display_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "elevation_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "events_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "extensions_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "filesystem_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcm_unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gcp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gfx_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gin_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "google_apis_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "gpu_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_browsertests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "headless_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "install_static_unittests" }, @@ -16801,7 +18416,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16810,6 +18427,12 @@ { "swarming": { "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], "shards": 3 }, "test": "interactive_ui_tests" @@ -16821,121 +18444,241 @@ ], "name": "webui_polymer1_interactive_ui_tests", "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "interactive_ui_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ipc_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "jingle_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "latency_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "leveldb_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "libjingle_xmpp_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_blink_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_service_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "media_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "message_center_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "midi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_core_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "mojo_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "nacl_loader_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "native_theme_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "net_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "pdf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ppapi_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "printing_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "remoting_unittests" }, @@ -16944,7 +18687,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16952,25 +18697,49 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sbox_validation_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "service_manager_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "services_unittests" }, @@ -16979,7 +18748,9 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "integrity": "high" + "cpu": "x86-64", + "integrity": "high", + "os": "Windows-10-15063" } ] }, @@ -16987,109 +18758,217 @@ }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "shell_dialogs_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "skia_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "snapshot_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sql_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "storage_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "sync_integration_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "traffic_annotation_auditor_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_base_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "ui_touch_selection_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "unit_tests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "url_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "views_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "viz_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_common_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "vr_pixeltests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wm_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "wtf_unittests" }, { "swarming": { - "can_use_on_swarming_builders": true + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] }, "test": "zucchini_unittests" }
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index b35b4e6..9ee9894 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -303,37 +303,6 @@ "ignore_task_failure": false, "io_timeout": 3600 } - }, - { - "args": [ - "--benchmarks=loading.desktop.network_service", - "-v", - "--upload-results", - "--output-format=histograms", - "--browser=release" - ], - "isolate_name": "performance_test_suite", - "merge": { - "script": "//tools/perf/process_perf_results.py" - }, - "name": "performance_test_suite", - "override_compile_targets": [ - "performance_test_suite" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de", - "id": "build186-b7", - "pool": "chrome.tests.perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 14400, - "ignore_task_failure": false, - "io_timeout": 3600 - } } ] }
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter index e116591..7b7bcf7d 100644 --- a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter +++ b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
@@ -19,8 +19,11 @@ # https://crbug.com/893575 -org.chromium.android_webview.test.CookieManagerStartupTest.testStartup -# https://crbug.com/893576 +# https://crbug.com/936317 +-org.chromium.android_webview.test.CookieManagerTest.testAcceptCookie_falseDoNotSendCookies -org.chromium.android_webview.test.CookieManagerTest.testAcceptCookie_falseWontSetCookies + +# https://crbug.com/893576 -org.chromium.android_webview.test.CookieManagerTest.testAcceptFileSchemeCookies -org.chromium.android_webview.test.CookieManagerTest.testThirdPartyCookie @@ -37,3 +40,11 @@ -org.chromium.android_webview.test.AwProxyControllerTest.testValidInput -org.chromium.android_webview.test.AwProxyControllerTest.testInvalidProxyUrls -org.chromium.android_webview.test.AwProxyControllerTest.testInvalidBypassRules + +# Flaky tests on android_mojo and android_mojo_rel bots +# https://crbug.com/936757, https://crbug.com/939355 +-org.chromium.android_webview.test.AwContentsClientFullScreenTest#testOnShowCustomViewAndPlayWithHtmlControl_videoInsideDiv +-org.chromium.android_webview.test.AwContentsClientFullScreenTest#testPowerSaveBlockerIsEnabledDuringEmbeddedPlayback +-org.chromium.android_webview.test.AwContentsClientFullScreenTest#testPowerSaveBlockerIsTransferredToEmbedded +-org.chromium.android_webview.test.AwContentsClientFullScreenTest#testPowerSaveBlockerIsTransferredToFullscreen +-org.chromium.android_webview.test.AwContentsClientFullScreenTest#testPowerSaveBlockerIsEnabledDuringFullscreenPlayback_videoInsideDiv
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index ef96db4..840723cd 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -707,28 +707,22 @@ }, }, 'CrWinAsan': { + 'mixins': [ + 'x86-64', + 'win10', + ], 'test_suites': { 'gtest_tests': 'chromium_win_gtests', }, - 'swarming': { - 'dimension_sets': [ - { - 'os': 'Windows-10-15063', - }, - ], - }, }, 'CrWinAsan(dll)': { + 'mixins': [ + 'x86-64', + 'win10', + ], 'test_suites': { 'gtest_tests': 'chromium_win_gtests', }, - 'swarming': { - 'dimension_sets': [ - { - 'os': 'Windows-10-15063', - }, - ], - }, }, 'ToTAndroid': { 'additional_compile_targets': [ @@ -884,16 +878,28 @@ }, }, 'ToTWin64': { + 'mixins': [ + 'x86-64', + 'win10', + ], 'test_suites': { 'gtest_tests': 'chromium_win_gtests', }, }, 'ToTWin64(dbg)': { + 'mixins': [ + 'x86-64', + 'win10', + ], 'test_suites': { 'gtest_tests': 'chromium_win_gtests', }, }, 'ToTWin64(dll)': { + 'mixins': [ + 'x86-64', + 'win10', + ], 'test_suites': { 'gtest_tests': 'chromium_win_gtests', },
diff --git a/testing/scripts/run_flatbuffers_unittests.py b/testing/scripts/run_flatbuffers_unittests.py index f0ead30..69436b43 100755 --- a/testing/scripts/run_flatbuffers_unittests.py +++ b/testing/scripts/run_flatbuffers_unittests.py
@@ -40,15 +40,16 @@ exe = os.path.join('.', 'flatbuffers_unittests') env = os.environ.copy() + failures = [] with common.temporary_file() as tempfile_path: rc = xvfb.run_executable([exe], env, stdoutfile=tempfile_path) # The flatbuffer tests do not really conform to anything parsable, except # that they will succeed with "ALL TESTS PASSED". with open(tempfile_path) as f: - failures = f.read() - if failures == "ALL TESTS PASSED\n": - failures = [] + output = f.read() + if output != "ALL TESTS PASSED\n": + failures = [output] with open(args.isolated_script_test_output, 'w') as fp: json.dump({'valid': True,'failures': failures}, fp)
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py index 4628d63d..0fe143d 100755 --- a/testing/scripts/run_performance_tests.py +++ b/testing/scripts/run_performance_tests.py
@@ -33,7 +33,9 @@ has to be passed in to the script so the script knows it is running an executable and not the run_benchmark command. -The results of running the benchmark are put in separate directories per +This script obeys the --isolated-script-test-output flag and merges test results +from all the benchmarks into the one output.json file. The test results and perf +results are also put in separate directories per benchmark. Two files will be present in each directory; perf_results.json, which is the perf specific results (with unenforced format, could be histogram or graph json), and test_results.json, which is a JSON test results @@ -59,12 +61,15 @@ CHROMIUM_SRC_DIR = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..')) -PERF_DIR = os.path.join(CHROMIUM_SRC_DIR, 'tools', 'perf') -# Add src/tools/perf where generate_legacy_perf_dashboard_json.py lives -sys.path.append(PERF_DIR) +PERF_DIR = os.path.join(CHROMIUM_SRC_DIR, 'tools', 'perf') +sys.path.append(PERF_DIR) import generate_legacy_perf_dashboard_json +PERF_CORE_DIR = os.path.join(PERF_DIR, 'core') +sys.path.append(PERF_CORE_DIR) +import results_merger + # Add src/testing/ into sys.path for importing xvfb and test_env. sys.path.append(os.path.join(os.path.dirname(__file__), '..')) import xvfb @@ -394,6 +399,12 @@ options = parse_arguments(args) isolated_out_dir = os.path.dirname(options.isolated_script_test_output) overall_return_code = 0 + # This is a list of test results files to be merged into a standard + # output.json file for use by infrastructure including FindIt. + # This list should not contain reference build runs + # since we do not monitor those. Also, merging test reference build results + # with standard build results may not work properly. + test_results_files = [] if options.non_telemetry: command_generator = GtestCommandGenerator(options) @@ -407,6 +418,7 @@ output_paths = OutputFilePaths(isolated_out_dir, benchmark_name).SetUp() overall_return_code = execute_gtest_perf_test( command_generator, output_paths, options.xvfb) + test_results_files.append(output_paths.test_results) else: # If the user has supplied a list of benchmark names, execute those instead # of using the shard map. @@ -419,6 +431,7 @@ return_code = execute_telemetry_benchmark( command_generator, output_paths, options.xvfb) overall_return_code = return_code or overall_return_code + test_results_files.append(output_paths.test_results) if options.run_ref_build: print ('Not running reference build. --run-ref-build argument is only ' 'supported for sharded benchmarks. It is simple to support ' @@ -458,6 +471,7 @@ return_code = execute_telemetry_benchmark( command_generator, output_paths, options.xvfb) overall_return_code = return_code or overall_return_code + test_results_files.append(output_paths.test_results) if options.run_ref_build: reference_benchmark_foldername = benchmark + '.reference' reference_output_paths = OutputFilePaths( @@ -465,7 +479,8 @@ reference_command_generator = TelemetryCommandGenerator( benchmark, options, stories=stories, is_reference=True) - # We intentionally ignore the return code of the reference build. + # We intentionally ignore the return code and test results of the + # reference build. execute_telemetry_benchmark( reference_command_generator, reference_output_paths, options.xvfb) @@ -473,6 +488,14 @@ raise Exception('Telemetry tests must provide either a shard map or a ' '--benchmarks list so that we know which stories to run.') + test_results_list = [] + for test_results_file in test_results_files: + with open(test_results_file, 'r') as fh: + test_results_list.append(json.load(fh)) + merged_test_results = results_merger.merge_test_results(test_results_list) + with open(options.isolated_script_test_output, 'w') as f: + json.dump(merged_test_results, f) + return overall_return_code
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 889e9113..dc64967 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -551,6 +551,26 @@ ] } ], + "AutocompleteRetentionPolicy": [ + { + "platforms": [ + "android", + "chromeos", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutocompleteRetentionPolicyEnabled" + ] + } + ] + } + ], "AutofillDropdownLayout": [ { "platforms": [ @@ -1275,6 +1295,9 @@ "name": "Enabled", "enable_features": [ "CompressParkableStringsInForeground" + ], + "disable_features": [ + "CompressParkableStringsInBackground" ] } ] @@ -3320,6 +3343,23 @@ ] } ], + "OutOfBlinkCors": [ + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "OutOfBlinkCors" + ] + } + ] + } + ], "OverflowIconsForMediaControls": [ { "platforms": [ @@ -3940,7 +3980,7 @@ ], "experiments": [ { - "name": "Enabled_Pool_Four_Fifths_Origin_ThreeQuarters", + "name": "Enabled_Pool_Four_Fifths_Origin_ThreeQuarters_20190307", "params": { "PerHostRatio": "0.75", "PoolSizeRatio": "0.8" @@ -3982,6 +4022,24 @@ ] } ], + "RemoveNTPFakebox": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "RemoveNTPFakebox", + "enable_features": [ + "RemoveNtpFakebox" + ] + } + ] + } + ], "RendererSchedulerWakeUpThrottling": [ { "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 1de7942cc1..c1e8b6ca 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -42,7 +42,7 @@ // Enable a new compositing mode called BlinkGenPropertyTrees where Blink // generates the compositor property trees. See: https://crbug.com/836884. const base::Feature kBlinkGenPropertyTrees{"BlinkGenPropertyTrees", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Enable LayoutNG. const base::Feature kLayoutNG{"LayoutNG", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index d217061..5fbcafd 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2257,6 +2257,8 @@ kCSSValueAppearanceTextFieldForTemporalRendered = 2823, kBuiltInModuleKvStorage = 2824, kBuiltInModuleVirtualScroller = 2825, + kAdClickNavigation = 2826, + kRTCStatsRelativePacketArrivalDelay = 2827, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/web/web_document_loader.h b/third_party/blink/public/web/web_document_loader.h index 88b836a..771af52c 100644 --- a/third_party/blink/public/web/web_document_loader.h +++ b/third_party/blink/public/web/web_document_loader.h
@@ -93,6 +93,9 @@ virtual bool HasUnreachableURL() const = 0; virtual WebURL UnreachableURL() const = 0; + // The error code for loading an error page. + virtual int ErrorCode() const = 0; + // Returns all redirects that occurred (both client and server) before // at last committing the current page. This will contain one entry // for each intermediate URL, and one entry for the last URL (so if
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h index 66c8584..9119816 100644 --- a/third_party/blink/public/web/web_navigation_params.h +++ b/third_party/blink/public/web/web_navigation_params.h
@@ -152,7 +152,8 @@ WebDocumentLoader* failed_document_loader, base::span<const char> html, const WebURL& base_url, - const WebURL& unreachable_url); + const WebURL& unreachable_url, + int error_code); #if INSIDE_BLINK // Shortcut for loading html with "text/html" mime type and "UTF8" encoding. @@ -200,6 +201,10 @@ // This URL can be retrieved through WebDocumentLoader::UnreachableURL. WebURL unreachable_url; + // The net error code for failed navigation. Must be non-zero when + // |unreachable_url| is non-null. + int error_code = 0; + // This block defines the document content. The alternatives in the order // of precedence are: // 1. If |is_static_data| is false:
diff --git a/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc b/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc index 37fa366..a0319ea7 100644 --- a/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc +++ b/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc
@@ -144,29 +144,27 @@ template <> bool DictionaryHelper::Get(const Dictionary& dictionary, const StringView& key, - unsigned& value) { - return GetNumericType<unsigned>(dictionary, key, value); + uint32_t& value) { + return GetNumericType<uint32_t>(dictionary, key, value); } template <> bool DictionaryHelper::Get(const Dictionary& dictionary, const StringView& key, - unsigned long& value) { + int64_t& value) { v8::Local<v8::Value> v8_value; if (!dictionary.Get(key, v8_value)) return false; - int64_t int64_value; - if (!v8_value->IntegerValue(dictionary.V8Context()).To(&int64_value)) + if (!v8_value->IntegerValue(dictionary.V8Context()).To(&value)) return false; - value = static_cast<unsigned long>(int64_value); return true; } template <> bool DictionaryHelper::Get(const Dictionary& dictionary, const StringView& key, - unsigned long long& value) { + uint64_t& value) { v8::Local<v8::Value> v8_value; if (!dictionary.Get(key, v8_value)) return false;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h index 65f3e3f..43c91e2c 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h +++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
@@ -372,7 +372,16 @@ inline float ToFloat(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { - return static_cast<float>(ToDouble(isolate, value, exception_state)); + double double_value = ToDouble(isolate, value, exception_state); + // TODO(crbug.com/939598): These cases should throw a TypeError instead + // of returning Infinity; but before fixing that, we must ensure that + // ToFloat is not called in cases where ToDouble should be called instead. + using Limits = std::numeric_limits<float>; + if (UNLIKELY(double_value > Limits::max())) + return Limits::infinity(); + if (UNLIKELY(double_value < Limits::lowest())) + return -Limits::infinity(); + return static_cast<float>(double_value); } // Convert a value to a single precision float, throwing on non-finite values.
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc index 50183ba..4f261839 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
@@ -213,6 +213,10 @@ V8CodeCache::SetCacheTimeStamp(cache_handler); break; case V8CodeCache::ProduceCacheOptions::kProduceCodeCache: { + // TODO(crbug.com/938269): Investigate why this can be empty here. + if (unbound_script.IsEmpty()) + break; + constexpr const char* kTraceEventCategoryGroup = "v8,devtools.timeline"; TRACE_EVENT_BEGIN1(kTraceEventCategoryGroup, trace_name, "fileName", source_url.GetString().Utf8());
diff --git a/third_party/blink/renderer/core/aom/accessible_node.cc b/third_party/blink/renderer/core/aom/accessible_node.cc index d4b6f8a0..d940a04 100644 --- a/third_party/blink/renderer/core/aom/accessible_node.cc +++ b/third_party/blink/renderer/core/aom/accessible_node.cc
@@ -285,9 +285,8 @@ for (wtf_size_t i = 0; i < node_list->length(); ++i) { AccessibleNode* accessible_node = node_list->item(i); if (accessible_node) { - Element* element = accessible_node->element(); - if (element) - targets.push_back(element); + if (Element* target_element = accessible_node->element()) + targets.push_back(target_element); } }
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc index a889c15..e295b58 100644 --- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc +++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -110,6 +110,16 @@ clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard); } +void SystemClipboard::WritePlainTextNoCommit(const String& plain_text, + SmartReplaceOption) { + // TODO(huangdarwin): add support for smart replace + String text = plain_text; +#if defined(OS_WIN) + ReplaceNewlinesWithWindowsStyleNewlines(text); +#endif + clipboard_->WriteText(mojom::ClipboardBuffer::kStandard, NonNullString(text)); +} + String SystemClipboard::ReadHTML(KURL& url, unsigned& fragment_start, unsigned& fragment_end) { @@ -191,9 +201,8 @@ clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard); } -void SystemClipboard::WriteImage(const SkBitmap& bitmap) { +void SystemClipboard::WriteImageNoCommit(const SkBitmap& bitmap) { clipboard_->WriteImage(mojom::ClipboardBuffer::kStandard, bitmap); - clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard); } String SystemClipboard::ReadCustomData(const String& type) { @@ -238,6 +247,10 @@ clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard); } +void SystemClipboard::CommitWrite() { + clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard); +} + bool SystemClipboard::IsValidBufferType(mojom::ClipboardBuffer buffer) { switch (buffer) { case mojom::ClipboardBuffer::kStandard:
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.h b/third_party/blink/renderer/core/clipboard/system_clipboard.h index 091e1b6..caf484c 100644 --- a/third_party/blink/renderer/core/clipboard/system_clipboard.h +++ b/third_party/blink/renderer/core/clipboard/system_clipboard.h
@@ -37,6 +37,8 @@ String ReadPlainText(); String ReadPlainText(mojom::ClipboardBuffer buffer); void WritePlainText(const String&, SmartReplaceOption = kCannotSmartReplace); + void WritePlainTextNoCommit(const String&, + SmartReplaceOption = kCannotSmartReplace); // If no data is read, an empty string will be returned and all out parameters // will be cleared. If applicable, the page URL will be assigned to the KURL @@ -56,11 +58,15 @@ // Write the image and its associated tag (bookmark/HTML types). void WriteImageWithTag(Image*, const KURL&, const String& title); // Write the image only. - void WriteImage(const SkBitmap&); + void WriteImageNoCommit(const SkBitmap&); String ReadCustomData(const String& type); void WriteDataObject(DataObject*); + // Clipboard write functions that don't commit (explicitly labelled as + // NoCommit) must use CommitWrite for changes to reach the OS clipboard. + void CommitWrite(); + private: SystemClipboard(); bool IsValidBufferType(mojom::ClipboardBuffer);
diff --git a/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h b/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h index 4056e9c..b88eb6e 100644 --- a/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h +++ b/third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h
@@ -67,14 +67,6 @@ DISALLOW_COPY_AND_ASSIGN(CSSUnsupportedStyleValue); }; -DEFINE_TYPE_CASTS(CSSUnsupportedStyleValue, - CSSStyleValue, - value, - value->GetType() == - CSSStyleValue::StyleValueType::kUnknownType, - value.GetType() == - CSSStyleValue::StyleValueType::kUnknownType); - template <> struct DowncastTraits<CSSUnsupportedStyleValue> { static bool AllowFrom(const CSSStyleValue& value) {
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index a60ac38..2a763d8f 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2391,7 +2391,7 @@ if (layout_object->HasLayer()) { ToLayoutBoxModelObject(layout_object) ->Layer() - ->SetNeeedsCompositingReasonsUpdate(); + ->SetNeedsCompositingReasonsUpdate(); } } }
diff --git a/third_party/blink/renderer/core/dom/range.cc b/third_party/blink/renderer/core/dom/range.cc index 14317a5f..911fa657 100644 --- a/third_party/blink/renderer/core/dom/range.cc +++ b/third_party/blink/renderer/core/dom/range.cc
@@ -1707,61 +1707,50 @@ LayoutText* const layout_text = ToText(node)->GetLayoutObject(); if (!layout_text) continue; + + // TODO(editing-dev): Offset in |LayoutText| doesn't match to DOM offset + // when |text-transform| applied. We should map DOM offset to offset in + // |LayouText| for |start_offset| and |end_offset|. + const unsigned start_offset = + (node == start_container) ? start_.Offset() : 0; + const unsigned end_offset = (node == end_container) + ? end_.Offset() + : std::numeric_limits<unsigned>::max(); if (!layout_text->IsTextFragment()) { - // TODO(editing-dev): Offset in |LayoutText| doesn't match to DOM offset - // when |text-transform| applied. We should map DOM offset to offset in - // |LayouText| for |start_offset| and |end_offset|. - const unsigned start_offset = - (node == start_container) ? start_.Offset() : 0; - const unsigned end_offset = (node == end_container) - ? end_.Offset() - : std::numeric_limits<unsigned>::max(); quads.AppendVector(ComputeTextQuads(*owner_document_, *layout_text, start_offset, end_offset)); continue; } + + // Handle ::first-letter const LayoutTextFragment& first_letter_part = *ToLayoutTextFragment(AssociatedLayoutObjectOf(*node, 0)); + const bool overlaps_with_first_letter = + start_offset < first_letter_part.FragmentLength() || + (start_offset == first_letter_part.FragmentLength() && + end_offset == start_offset); + if (overlaps_with_first_letter) { + const unsigned start_in_first_letter = start_offset; + const unsigned end_in_first_letter = + std::min(end_offset, first_letter_part.FragmentLength()); + quads.AppendVector(ComputeTextQuads(*owner_document_, first_letter_part, + start_in_first_letter, + end_in_first_letter)); + } const LayoutTextFragment& remaining_part = *ToLayoutTextFragment(layout_text); - // Set offsets in |LayoutTextFragment| to cover whole text in - // |LayoutTextFragment|. - unsigned first_letter_part_start = 0; - unsigned first_letter_part_end = first_letter_part.FragmentLength(); - unsigned remaining_part_start = 0; - unsigned remaining_part_end = remaining_part.FragmentLength(); - if (node == start_container) { - if (start_.Offset() < first_letter_part_end) { - // |this| range starts in first-letter part. - first_letter_part_start = start_.Offset(); - } else { - first_letter_part_start = first_letter_part_end; - DCHECK_GE(static_cast<unsigned>(start_.Offset()), - remaining_part.Start()); - remaining_part_start = start_.Offset() - remaining_part.Start(); - } - } - if (node == end_container) { - if (end_.Offset() <= first_letter_part_end) { - // |this| range ends in first-letter part. - first_letter_part_end = end_.Offset(); - remaining_part_end = remaining_part_start; - } else { - DCHECK_GE(static_cast<unsigned>(end_.Offset()), remaining_part.Start()); - remaining_part_end = end_.Offset() - remaining_part.Start(); - } - } - DCHECK_LE(first_letter_part_start, first_letter_part_end); - DCHECK_LE(remaining_part_start, remaining_part_end); - if (first_letter_part_start < first_letter_part_end) { - quads.AppendVector(ComputeTextQuads(*owner_document_, first_letter_part, - first_letter_part_start, - first_letter_part_end)); - } - if (remaining_part_start < remaining_part_end) { + if (end_offset > remaining_part.Start()) { + const unsigned start_in_remaining_part = + std::max(start_offset, remaining_part.Start()) - + remaining_part.Start(); + // TODO(editing-dev): As we previously set |end_offset == UINT_MAX| as a + // hacky support for |text-transform|, we need the same hack here. + const unsigned end_in_remaining_part = + end_offset == UINT_MAX ? end_offset + : end_offset - remaining_part.Start(); quads.AppendVector(ComputeTextQuads(*owner_document_, remaining_part, - remaining_part_start, - remaining_part_end)); + start_in_remaining_part, + end_in_remaining_part)); } } }
diff --git a/third_party/blink/renderer/core/dom/range_test.cc b/third_party/blink/renderer/core/dom/range_test.cc index 187b7735..3564642 100644 --- a/third_party/blink/renderer/core/dom/range_test.cc +++ b/third_party/blink/renderer/core/dom/range_test.cc
@@ -447,4 +447,57 @@ << "Partial first-letter part and remaining part"; } +TEST_F(RangeTest, CollapsedRangeGetBorderAndTextQuadsWithFirstLetter) { + GetDocument().body()->SetInnerHTMLFromString(R"HTML( + <style> + body { font-size: 20px; } + #sample::first-letter { font-size: 500%; } + </style> + <p id=sample>abc</p> + <p id=expected><span style='font-size: 500%'>a</span>bc</p> + )HTML"); + GetDocument().UpdateStyleAndLayout(); + + Element* const expected = GetDocument().getElementById("expected"); + Element* const sample = GetDocument().getElementById("sample"); + + const Vector<FloatQuad> expected_quads = + GetBorderAndTextQuads(Position(expected, 0), Position(expected, 2)); + const Vector<FloatQuad> sample_quads = + GetBorderAndTextQuads(Position(sample, 0), Position(sample, 1)); + ASSERT_EQ(2u, sample_quads.size()); + ASSERT_EQ(3u, expected_quads.size()) + << "expected_quads has SPAN, SPAN.firstChild and P.lastChild"; + EXPECT_EQ(expected_quads[0].EnclosingBoundingBox().Size(), + sample_quads[0].EnclosingBoundingBox().Size()) + << "Check size of first-letter part"; + EXPECT_EQ(expected_quads[2].EnclosingBoundingBox().Size(), + sample_quads[1].EnclosingBoundingBox().Size()) + << "Check size of first-letter part"; + + EXPECT_EQ(ComputeSizesOfQuads(GetBorderAndTextQuads( + Position(expected->firstChild()->firstChild(), 0), + Position(expected->firstChild()->firstChild(), 0))), + ComputeSizesOfQuads( + GetBorderAndTextQuads(Position(sample->firstChild(), 0), + Position(sample->firstChild(), 0)))) + << "Collapsed range before first-letter part"; + + EXPECT_EQ(ComputeSizesOfQuads(GetBorderAndTextQuads( + Position(expected->firstChild()->firstChild(), 1), + Position(expected->firstChild()->firstChild(), 1))), + ComputeSizesOfQuads( + GetBorderAndTextQuads(Position(sample->firstChild(), 1), + Position(sample->firstChild(), 1)))) + << "Collapsed range after first-letter part"; + + EXPECT_EQ(ComputeSizesOfQuads(GetBorderAndTextQuads( + Position(expected->firstChild()->nextSibling(), 1), + Position(expected->firstChild()->nextSibling(), 1))), + ComputeSizesOfQuads( + GetBorderAndTextQuads(Position(sample->firstChild(), 2), + Position(sample->firstChild(), 2)))) + << "Collapsed range in remaining text part"; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/editing/selection_controller.cc b/third_party/blink/renderer/core/editing/selection_controller.cc index d3a2489a..acf54cc 100644 --- a/third_party/blink/renderer/core/editing/selection_controller.cc +++ b/third_party/blink/renderer/core/editing/selection_controller.cc
@@ -546,10 +546,17 @@ Selection().Granularity()) : SelectionInFlatTree::Builder().Collapse(adjusted_position).Build(); + // When |adjusted_selection| is caret, it's already canonical. No need to re- + // canonicalize it. + const SelectionInFlatTree new_visible_selection = + adjusted_selection.IsRange() + ? CreateVisibleSelection(adjusted_selection).AsSelection() + : adjusted_selection; + const bool selection_is_directional = should_extend_selection ? Selection().IsDirectional() : false; SetNonDirectionalSelectionIfNeeded( - CreateVisibleSelection(adjusted_selection).AsSelection(), + new_visible_selection, SetSelectionOptions::Builder() .SetGranularity(Selection().Granularity()) .SetIsDirectional(selection_is_directional)
diff --git a/third_party/blink/renderer/core/exported/web_document_loader_impl.cc b/third_party/blink/renderer/core/exported/web_document_loader_impl.cc index b8c8d9b..12a49925 100644 --- a/third_party/blink/renderer/core/exported/web_document_loader_impl.cc +++ b/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
@@ -91,6 +91,10 @@ return DocumentLoader::UnreachableURL(); } +int WebDocumentLoaderImpl::ErrorCode() const { + return DocumentLoader::ErrorCode(); +} + void WebDocumentLoaderImpl::RedirectChain(WebVector<WebURL>& result) const { result.Assign(redirect_chain_); }
diff --git a/third_party/blink/renderer/core/exported/web_document_loader_impl.h b/third_party/blink/renderer/core/exported/web_document_loader_impl.h index 067d6af3..17a17c7a 100644 --- a/third_party/blink/renderer/core/exported/web_document_loader_impl.h +++ b/third_party/blink/renderer/core/exported/web_document_loader_impl.h
@@ -67,6 +67,7 @@ const WebURLResponse& GetResponse() const override; bool HasUnreachableURL() const override; WebURL UnreachableURL() const override; + int ErrorCode() const override; void RedirectChain(WebVector<WebURL>&) const override; bool IsClientRedirect() const override; bool ReplacesCurrentHistoryItem() const override;
diff --git a/third_party/blink/renderer/core/exported/web_navigation_params.cc b/third_party/blink/renderer/core/exported/web_navigation_params.cc index b41b8a9..3c85a4c 100644 --- a/third_party/blink/renderer/core/exported/web_navigation_params.cc +++ b/third_party/blink/renderer/core/exported/web_navigation_params.cc
@@ -57,9 +57,12 @@ WebDocumentLoader* failed_document_loader, base::span<const char> html, const WebURL& base_url, - const WebURL& unreachable_url) { + const WebURL& unreachable_url, + int error_code) { auto result = WebNavigationParams::CreateWithHTMLString(html, base_url); + DCHECK(!unreachable_url.IsEmpty() || error_code != 0); result->unreachable_url = unreachable_url; + result->error_code = error_code; static_cast<WebDocumentLoaderImpl*>(failed_document_loader) ->FillNavigationParamsForErrorPage(result.get()); return result;
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc index 1ccf2c0..69563a6 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -355,17 +355,18 @@ while (true) { uint32_t num_bytes; const void* buffer; - MojoResult result = consumer_handle_->BeginReadData( + MojoResult pipe_result = consumer_handle_->BeginReadData( &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE); - if (result == MOJO_RESULT_SHOULD_WAIT) { + if (pipe_result == MOJO_RESULT_SHOULD_WAIT) { if (!IsSyncLoad()) return; - result = mojo::Wait(consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE); - if (result == MOJO_RESULT_OK) + pipe_result = + mojo::Wait(consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE); + if (pipe_result == MOJO_RESULT_OK) continue; } - if (result == MOJO_RESULT_FAILED_PRECONDITION) { + if (pipe_result == MOJO_RESULT_FAILED_PRECONDITION) { // Pipe closed. if (!received_all_data_) { Failed(FileErrorCode::kNotReadableErr, @@ -373,7 +374,7 @@ } return; } - if (result != MOJO_RESULT_OK) { + if (pipe_result != MOJO_RESULT_OK) { Failed(FileErrorCode::kNotReadableErr, FailureType::kMojoPipeUnexpectedReadError); return;
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index c0aecdf..c6cc53b 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1828,4 +1828,9 @@ } } +void LocalFrame::MaybeLogAdClickNavigation() { + if (HasTransientUserActivation() && IsAdSubframe()) + UseCounter::Count(GetDocument(), WebFeature::kAdClickNavigation); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index cc997e0..072816b 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -437,6 +437,15 @@ void SetLifecycleState(mojom::FrameLifecycleState state); + // For a navigation initiated from this LocalFrame with user gesture, record + // the UseCounter AdClickNavigation if this frame is an adframe. + // + // TODO(crbug.com/939370): Currently this is called in a couple of sites, + // which is fragile and prone to break. If we have the ad status in + // RemoteFrame, we could call it at FrameLoader::StartNavigation where all + // navigations go through. + void MaybeLogAdClickNavigation(); + private: friend class FrameNavigationDisabler;
diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc index 01384aaf..fb8f1fd0c 100644 --- a/third_party/blink/renderer/core/frame/location.cc +++ b/third_party/blink/renderer/core/frame/location.cc
@@ -321,6 +321,8 @@ WebFrameLoadType frame_load_type = WebFrameLoadType::kStandard; if (set_location_policy == SetLocationPolicy::kReplaceThisFrame) frame_load_type = WebFrameLoadType::kReplaceCurrentItem; + + current_window->GetFrame()->MaybeLogAdClickNavigation(); dom_window_->GetFrame()->ScheduleNavigation(*current_window->document(), completed_url, frame_load_type, UserGestureStatus::kNone);
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index 030c1755..59c9d03 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -916,7 +916,7 @@ }, { name: "darkModePagePolicy", - initial: "DarkModePagePolicy::kFilterAll", + initial: "DarkModePagePolicy::kFilterByBackground", type: "DarkModePagePolicy", invalidate: "Paint", },
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index ab8734e..acfe7a2a 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -462,6 +462,8 @@ frame_request.SetInputStartTime(event.PlatformTimeStamp()); // TODO(japhet): Link clicks can be emulated via JS without a user gesture. // Why doesn't this go through NavigationScheduler? + + frame->MaybeLogAdClickNavigation(); frame->Loader().StartNavigation(frame_request, WebFrameLoadType::kStandard, NavigationPolicyFromEvent(&event)); }
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 965e7a9..0ffee8d 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -1257,7 +1257,9 @@ frame_->LocalFrameRoot().GetEventHandler().SetPointerCapture(pointer_id, target); } else { - pointer_event_manager_->SetPointerCapture(pointer_id, target); + if (pointer_event_manager_->SetPointerCapture(pointer_id, target) && + pointer_id == PointerEventFactory::kMouseId) + CaptureMouseEventsToWidget(true); } } @@ -1267,7 +1269,9 @@ frame_->LocalFrameRoot().GetEventHandler().ReleasePointerCapture(pointer_id, target); } else { - pointer_event_manager_->ReleasePointerCapture(pointer_id, target); + if (pointer_event_manager_->ReleasePointerCapture(pointer_id, target) && + pointer_id == PointerEventFactory::kMouseId) + CaptureMouseEventsToWidget(false); } }
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.h b/third_party/blink/renderer/core/input/mouse_event_manager.h index 278f8c30..85e6dd06 100644 --- a/third_party/blink/renderer/core/input/mouse_event_manager.h +++ b/third_party/blink/renderer/core/input/mouse_event_manager.h
@@ -43,7 +43,7 @@ virtual ~MouseEventManager(); void Trace(blink::Visitor*) override; - enum UpdateHoverReason { kScrollOffsetChanged, kLayoutOrStyleChanged }; + enum class UpdateHoverReason { kScrollOffsetChanged, kLayoutOrStyleChanged }; WebInputEventResult DispatchMouseEvent(EventTarget*, const AtomicString&,
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc index 3b9b732..21f30c6 100644 --- a/third_party/blink/renderer/core/input/pointer_event_manager.cc +++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -892,7 +892,7 @@ target); } -void PointerEventManager::SetPointerCapture(PointerId pointer_id, +bool PointerEventManager::SetPointerCapture(PointerId pointer_id, Element* target) { UseCounter::Count(frame_->GetDocument(), WebFeature::kPointerEventSetCapture); if (pointer_event_factory_.IsActiveButtonsState(pointer_id)) { @@ -901,10 +901,12 @@ WebFeature::kPointerEventSetCaptureOutsideDispatch); } pending_pointer_capture_target_.Set(pointer_id, target); + return true; } + return false; } -void PointerEventManager::ReleasePointerCapture(PointerId pointer_id, +bool PointerEventManager::ReleasePointerCapture(PointerId pointer_id, Element* target) { // Only the element that is going to get the next pointer event can release // the capture. Note that this might be different from @@ -913,8 +915,11 @@ // but |m_pendingPointerCaptureTarget| indicated the element that gets the // very next pointer event. They will be the same if there was no change in // capturing of a particular |pointerId|. See crbug.com/614481. - if (pending_pointer_capture_target_.at(pointer_id) == target) + if (pending_pointer_capture_target_.at(pointer_id) == target) { ReleasePointerCapture(pointer_id); + return true; + } + return false; } void PointerEventManager::ReleaseMousePointerCapture() {
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.h b/third_party/blink/renderer/core/input/pointer_event_manager.h index a6b8ba1c6..971f0d5 100644 --- a/third_party/blink/renderer/core/input/pointer_event_manager.h +++ b/third_party/blink/renderer/core/input/pointer_event_manager.h
@@ -75,8 +75,8 @@ void ElementRemoved(Element*); - void SetPointerCapture(PointerId, Element*); - void ReleasePointerCapture(PointerId, Element*); + bool SetPointerCapture(PointerId, Element*); + bool ReleasePointerCapture(PointerId, Element*); void ReleaseMousePointerCapture(); // See Element::hasPointerCapture(PointerId).
diff --git a/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc b/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc index 7a71cc10..dc13370 100644 --- a/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc +++ b/third_party/blink/renderer/core/invisible_dom/invisible_dom.cc
@@ -46,9 +46,9 @@ for (Node& node : range.Nodes()) { if (!InvisibleDOM::IsInsideInvisibleSubtree(node)) continue; - for (Node& node : FlatTreeTraversal::AncestorsOf(node)) { - if (node.IsElementNode()) { - elements_to_activate.push_back(ToElement(node)); + for (Node& ancestor_node : FlatTreeTraversal::AncestorsOf(node)) { + if (ancestor_node.IsElementNode()) { + elements_to_activate.push_back(ToElement(ancestor_node)); break; } }
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index f2da6f3a..85a22c1 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1579,7 +1579,7 @@ scoped_refptr<const ComputedStyle> child_style = child->Style(); if (child->IsFloating() || - (child->IsBox() && ToLayoutBox(child)->AvoidsFloats())) { + (child->IsBox() && ToLayoutBox(child)->CreatesNewFormattingContext())) { LayoutUnit float_total_width = float_left_width + float_right_width; EClear c = ResolvedClear(*child_style, style_to_use); if (c == EClear::kBoth || c == EClear::kLeft) { @@ -1624,7 +1624,7 @@ w = child_max_preferred_logical_width + margin; if (!child->IsFloating()) { - if (child->IsBox() && ToLayoutBox(child)->AvoidsFloats()) { + if (child->IsBox() && ToLayoutBox(child)->CreatesNewFormattingContext()) { // Determine a left and right max value based off whether or not the // floats can fit in the margins of the object. For negative margins, we // will attempt to overlap the float if the negative margin is smaller
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h index 7294694..aa9a33e 100644 --- a/third_party/blink/renderer/core/layout/layout_block.h +++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -138,8 +138,6 @@ LayoutUnit MinLineHeightForReplacedObject(bool is_first_line, LayoutUnit replaced_height) const; - virtual bool CreatesNewFormattingContext() const { return true; } - const char* GetName() const override; protected:
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc index b34d3c4..9e2b1b33 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -688,7 +688,7 @@ LayoutUnit child_margin_start = MarginStartForChild(child); LayoutUnit new_position = start_position + child_margin_start; - if (child.AvoidsFloats() && ContainsFloats()) { + if (child.CreatesNewFormattingContext() && ContainsFloats()) { LayoutUnit position_to_avoid_floats = StartOffsetForAvoidingFloats( LogicalTopForChild(child), LogicalHeightForChild(child)); @@ -739,8 +739,8 @@ // TODO(mstensho): rework the code to return early when there is no need for // marking, instead of this |markDescendantsWithFloats| flag. bool mark_descendants_with_floats = false; - if (new_logical_top != child.LogicalTop() && !child.AvoidsFloats() && - child.ContainsFloats()) { + if (new_logical_top != child.LogicalTop() && + !child.CreatesNewFormattingContext() && child.ContainsFloats()) { mark_descendants_with_floats = true; } else if (UNLIKELY(new_logical_top.MightBeSaturated())) { // The logical top might be saturated for very large elements. Comparing @@ -748,7 +748,8 @@ // removing margins, borders etc. from a saturated number might yield // incorrect results. If this is the case, always mark for layout. mark_descendants_with_floats = true; - } else if (!child.AvoidsFloats() || child.ShrinkToAvoidFloats()) { + } else if (!child.CreatesNewFormattingContext() || + child.ShrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always // mark it for layout. LayoutUnit lowest_float = @@ -1349,7 +1350,7 @@ // Inline blocks are covered by the isAtomicInlineLevel() check in the // avoidFloats method. - if (AvoidsFloats() || IsDocumentElement() || IsLayoutView() || + if (CreatesNewFormattingContext() || IsDocumentElement() || IsLayoutView() || IsFloatingOrOutOfFlowPositioned() || IsTableCell()) { if (floating_objects_) { floating_objects_->Clear(); @@ -1384,7 +1385,6 @@ bool sibling_float_may_intrude = false; LayoutObject* prev = PreviousSibling(); while (prev && (!prev->IsBox() || !prev->IsLayoutBlock() || - ToLayoutBlock(prev)->AvoidsFloats() || ToLayoutBlock(prev)->CreatesNewFormattingContext())) { if (prev->IsFloating()) sibling_float_may_intrude = true; @@ -1947,7 +1947,8 @@ bool logical_top_intrudes_into_float = logical_top < before_collapse_logical_top; if (logical_top_intrudes_into_float && ContainsFloats() && - !child.AvoidsFloats() && LowestFloatLogicalBottom() > logical_top) { + !child.CreatesNewFormattingContext() && + LowestFloatLogicalBottom() > logical_top) { child.SetNeedsLayoutAndFullPaintInvalidation( layout_invalidation_reason::kAncestorMarginCollapsing); } @@ -2847,12 +2848,12 @@ FloatingObjectSetIterator end = floating_object_set.end(); for (LayoutObject* next = NextSibling(); next; next = next->NextSibling()) { - if (!next->IsLayoutBlockFlow() || - (!float_to_remove && (next->IsFloatingOrOutOfFlowPositioned() || - ToLayoutBlockFlow(next)->AvoidsFloats()))) + LayoutBlockFlow* next_block = ToLayoutBlockFlowOrNull(next); + if (!next_block || + (!float_to_remove && (next_block->IsFloatingOrOutOfFlowPositioned() || + next_block->CreatesNewFormattingContext()))) continue; - LayoutBlockFlow* next_block = ToLayoutBlockFlow(next); for (FloatingObjectSetIterator it = floating_object_set.begin(); it != end; ++it) { LayoutBox* floating_box = (*it)->GetLayoutObject(); @@ -2880,7 +2881,7 @@ LayoutUnit result = clear != EClear::kNone ? (logical_bottom - logical_top).ClampNegativeToZero() : LayoutUnit(); - if (!result && child->AvoidsFloats()) { + if (!result && child->CreatesNewFormattingContext()) { LayoutUnit new_logical_top = logical_top; LayoutRect border_box = child->BorderBoxRect(); LayoutUnit child_logical_width_at_old_logical_top_offset = @@ -2972,8 +2973,9 @@ void LayoutBlockFlow::StyleWillChange(StyleDifference diff, const ComputedStyle& new_style) { const ComputedStyle* old_style = Style(); - can_propagate_float_into_sibling_ = - old_style ? !IsFloatingOrOutOfFlowPositioned() && !AvoidsFloats() : false; + can_propagate_float_into_sibling_ = old_style && + !IsFloatingOrOutOfFlowPositioned() && + !CreatesNewFormattingContext(); if (old_style && Parent() && diff.NeedsFullLayout() && old_style->GetPosition() != new_style.GetPosition() && ContainsFloats() && !IsFloating() && !IsOutOfFlowPositioned() && @@ -2995,7 +2997,7 @@ // and clear all floats from its next sibling blocks that exist in our // floating objects list. See crbug.com/56299 and crbug.com/62875. bool can_propagate_float_into_sibling = - !IsFloatingOrOutOfFlowPositioned() && !AvoidsFloats(); + !IsFloatingOrOutOfFlowPositioned() && !CreatesNewFormattingContext(); bool sibling_float_propagation_changed = diff.NeedsFullLayout() && can_propagate_float_into_sibling_ && !can_propagate_float_into_sibling && HasOverhangingFloats(); @@ -3966,9 +3968,10 @@ if (child.LogicalBottom() <= old_logical_top) { LayoutObject* next = child.NextSibling(); if (next && next->IsLayoutBlockFlow()) { - LayoutBlockFlow* nextBlock = ToLayoutBlockFlow(next); - if (!nextBlock->AvoidsFloats() || nextBlock->ShrinkToAvoidFloats()) - nextBlock->MarkAllDescendantsWithFloatsForLayout(); + LayoutBlockFlow* next_block = ToLayoutBlockFlow(next); + if (!next_block->CreatesNewFormattingContext() || + next_block->ShrinkToAvoidFloats()) + next_block->MarkAllDescendantsWithFloatsForLayout(); } } @@ -4030,7 +4033,7 @@ void LayoutBlockFlow::AddIntrudingFloats(LayoutBlockFlow* prev, LayoutUnit logical_left_offset, LayoutUnit logical_top_offset) { - DCHECK(!AvoidsFloats()); + DCHECK(!CreatesNewFormattingContext()); // If we create our own block formatting context then our contents don't // interact with floats outside it, even those from our parent. @@ -4474,11 +4477,10 @@ if (IsRenderedLegend()) return true; - return false; -} + if (ShouldBeConsideredAsReplaced()) + return true; -bool LayoutBlockFlow::AvoidsFloats() const { - return ShouldBeConsideredAsReplaced() || CreatesNewFormattingContext(); + return false; } void LayoutBlockFlow::MoveChildrenTo(LayoutBoxModelObject* to_box_model_object,
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h index 52beaa4..9f500a39 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.h +++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -361,7 +361,6 @@ void PositionSpannerDescendant(LayoutMultiColumnSpannerPlaceholder& child); bool CreatesNewFormattingContext() const override; - bool AvoidsFloats() const final; using LayoutBoxModelObject::MoveChildrenTo; void MoveChildrenTo(LayoutBoxModelObject* to_box_model_object,
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 8584bb6..b5af813 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3127,7 +3127,7 @@ MinimumValueForLength(margin_end_length, container_width); LayoutUnit available_width = container_width; - if (AvoidsFloats() && containing_block->IsLayoutBlockFlow() && + if (CreatesNewFormattingContext() && containing_block->IsLayoutBlockFlow() && ToLayoutBlockFlow(containing_block)->ContainsFloats()) { available_width = ContainingBlockAvailableLineWidth(); if (ShrinkToAvoidFloats() && available_width < container_width) { @@ -5114,7 +5114,7 @@ bool LayoutBox::ShrinkToAvoidFloats() const { // Floating objects don't shrink. Objects that don't avoid floats don't // shrink. - if (IsInline() || !AvoidsFloats() || IsFloating()) + if (IsInline() || !CreatesNewFormattingContext() || IsFloating()) return false; // Only auto width objects can possibly shrink to avoid floats. @@ -5143,10 +5143,6 @@ IsHTMLImageElement(ToElement(node))); } -bool LayoutBox::AvoidsFloats() const { - return true; -} - bool LayoutBox::HasNonCompositedScrollbars() const { if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) { if (scrollable_area->HasHorizontalScrollbar() &&
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index c7fc0ad..c0f5f8d 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1203,7 +1203,7 @@ // inline-block. bool ShrinkToAvoidFloats() const; - virtual bool AvoidsFloats() const; + virtual bool CreatesNewFormattingContext() const { return true; } bool ShouldBeConsideredAsReplaced() const; void UpdateFragmentationInfoForChild(LayoutBox&);
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 29169fd5..376712e 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1128,18 +1128,19 @@ } LayoutBlock* LayoutObject::ContainingBlock(AncestorSkipInfo* skip_info) const { - LayoutObject* object = Parent(); - if (!object && IsLayoutScrollbarPart()) - object = ToLayoutScrollbarPart(this)->GetScrollableArea()->GetLayoutBox(); if (!IsTextOrSVGChild()) { if (style_->GetPosition() == EPosition::kFixed) return ContainingBlockForFixedPosition(skip_info); if (style_->GetPosition() == EPosition::kAbsolute) return ContainingBlockForAbsolutePosition(skip_info); } + LayoutObject* object; if (IsColumnSpanAll()) { object = SpannerPlaceholder()->ContainingBlock(); } else { + object = Parent(); + if (!object && IsLayoutScrollbarPart()) + object = ToLayoutScrollbarPart(this)->GetScrollableArea()->GetLayoutBox(); while (object && ((object->IsInline() && !object->IsAtomicInlineLevel()) || !object->IsLayoutBlock())) { if (skip_info)
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 71e57d4..705157a 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -500,6 +500,10 @@ return ShouldApplyPaintContainment() && ShouldApplyLayoutContainment() && ShouldApplyStyleContainment(); } + inline bool ShouldApplyStrictContainment() const { + return ShouldApplyPaintContainment() && ShouldApplyLayoutContainment() && + ShouldApplyStyleContainment() && ShouldApplySizeContainment(); + } private: //////////////////////////////////////////
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc index b8aa6f02..7ba19329 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
@@ -231,7 +231,7 @@ } scoped_refptr<ShapeResult> NGInlineItemSegments::ShapeText( - HarfBuzzShaper* shaper, + const HarfBuzzShaper* shaper, const Font* font, TextDirection direction, unsigned start_offset,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h index 3d6e1c9..b22da6db 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
@@ -138,7 +138,7 @@ unsigned item_index) const; // Shape runs in the range and return the concatenated |ShapeResult|. - scoped_refptr<ShapeResult> ShapeText(HarfBuzzShaper* shaper, + scoped_refptr<ShapeResult> ShapeText(const HarfBuzzShaper* shaper, const Font* font, TextDirection direction, unsigned start_offset,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index 951deac..41762634 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -1031,22 +1031,23 @@ NGExclusionSpace empty_exclusion_space; NGPositionedFloatVector empty_leading_floats; - Vector<LayoutObject*> floats_for_min_max; NGLineLayoutOpportunity line_opportunity(available_inline_size); LayoutUnit result; LayoutUnit previous_floats_inline_size = input.float_left_inline_size + input.float_right_inline_size; DCHECK_GE(previous_floats_inline_size, 0); - NGLineBreaker line_breaker( - node, mode, space, line_opportunity, empty_leading_floats, - /* handled_leading_floats_index */ 0u, - /* break_token */ nullptr, &empty_exclusion_space, - input.percentage_resolution_block_size, &floats_for_min_max); + NGLineBreaker line_breaker(node, mode, space, line_opportunity, + empty_leading_floats, + /* handled_leading_floats_index */ 0u, + /* break_token */ nullptr, &empty_exclusion_space); + + Vector<LayoutObject*> floats_for_min_max; do { floats_for_min_max.Shrink(0); NGLineInfo line_info; - line_breaker.NextLine(&line_info); + line_breaker.NextLine(input.percentage_resolution_block_size, + &floats_for_min_max, &line_info); if (line_info.Results().IsEmpty()) break;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 573869b..2137aff 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -77,19 +77,70 @@ NeedsAccurateEndPosition(line_end_item); } +inline void ComputeCanBreakAfter(NGInlineItemResult* item_result, + bool auto_wrap, + const LazyLineBreakIterator& break_iterator) { + item_result->can_break_after = + auto_wrap && break_iterator.IsBreakable(item_result->end_offset); +} + +// To correctly determine if a float is allowed to be on the same line as its +// content, we need to determine if it has any ancestors with inline-end +// padding, border, or margin. +// The inline-end size from all of these ancestors contribute to the "used +// size" of the float, and may cause the float to be pushed down. +LayoutUnit ComputeFloatAncestorInlineEndSize(const NGConstraintSpace& space, + const Vector<NGInlineItem>& items, + wtf_size_t item_index) { + LayoutUnit inline_end_size; + while (item_index < items.size()) { + const NGInlineItem& item = items[item_index++]; + + if (item.Type() == NGInlineItem::kCloseTag) { + if (item.HasEndEdge()) + inline_end_size += ComputeInlineEndSize(space, item.Style()); + continue; + } + + // For this calculation, any open tag (even if its empty) stops this + // calculation, and allows the float to appear on the same line. E.g. + // <span style="padding-right: 20px;"><f></f><span></span></span> + // + // Any non-empty item also allows the float to be on the same line. + if (item.Type() == NGInlineItem::kOpenTag || !item.IsEmptyItem()) + break; + } + return inline_end_size; +} + +scoped_refptr<const NGPhysicalTextFragment> CreateHyphenFragment( + NGInlineNode node, + WritingMode writing_mode, + const NGInlineItem& item) { + DCHECK(item.Style()); + const ComputedStyle& style = *item.Style(); + TextDirection direction = style.Direction(); + String hyphen_string = style.HyphenString(); + HarfBuzzShaper shaper(hyphen_string); + scoped_refptr<ShapeResult> hyphen_result = + shaper.Shape(&style.GetFont(), direction); + NGTextFragmentBuilder builder(node, writing_mode); + builder.SetText(item.GetLayoutObject(), hyphen_string, &style, + /* is_ellipsis_style */ false, + ShapeResultView::Create(hyphen_result.get())); + return builder.ToTextFragment(); +} + } // namespace -NGLineBreaker::NGLineBreaker( - NGInlineNode node, - NGLineBreakerMode mode, - const NGConstraintSpace& space, - const NGLineLayoutOpportunity& line_opportunity, - const NGPositionedFloatVector& leading_floats, - unsigned handled_leading_floats_index, - const NGInlineBreakToken* break_token, - NGExclusionSpace* exclusion_space, - LayoutUnit percentage_resolution_block_size_for_min_max, - Vector<LayoutObject*>* out_floats_for_min_max) +NGLineBreaker::NGLineBreaker(NGInlineNode node, + NGLineBreakerMode mode, + const NGConstraintSpace& space, + const NGLineLayoutOpportunity& line_opportunity, + const NGPositionedFloatVector& leading_floats, + unsigned handled_leading_floats_index, + const NGInlineBreakToken* break_token, + NGExclusionSpace* exclusion_space) : line_opportunity_(line_opportunity), node_(node), is_first_formatted_line_((!break_token || (!break_token->ItemIndex() && @@ -108,10 +159,7 @@ spacing_(items_data_.text_content), leading_floats_(leading_floats), handled_leading_floats_index_(handled_leading_floats_index), - base_direction_(node_.BaseDirection()), - percentage_resolution_block_size_for_min_max_( - percentage_resolution_block_size_for_min_max), - out_floats_for_min_max_(out_floats_for_min_max) { + base_direction_(node_.BaseDirection()) { break_iterator_.SetBreakSpace(BreakSpaceType::kBeforeSpaceRun); if (break_token) { @@ -143,37 +191,34 @@ NGLineBreaker::~NGLineBreaker() = default; inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item, - unsigned end_offset) { + unsigned end_offset, + NGLineInfo* line_info) { DCHECK_LE(end_offset, item.EndOffset()); - return &item_results_->emplace_back(&item, item_index_, offset_, end_offset, - break_anywhere_if_overflow_, - ShouldCreateLineBox(*item_results_), - HasUnpositionedFloats(*item_results_)); + NGInlineItemResults* item_results = line_info->MutableResults(); + return &item_results->emplace_back( + &item, item_index_, offset_, end_offset, break_anywhere_if_overflow_, + ShouldCreateLineBox(*item_results), HasUnpositionedFloats(*item_results)); } -inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item) { - return AddItem(item, item.EndOffset()); +inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item, + NGLineInfo* line_info) { + return AddItem(item, item.EndOffset(), line_info); } void NGLineBreaker::SetLineEndFragment( - scoped_refptr<const NGPhysicalTextFragment> fragment) { + scoped_refptr<const NGPhysicalTextFragment> fragment, + NGLineInfo* line_info) { bool is_horizontal = IsHorizontalWritingMode(constraint_space_.GetWritingMode()); - if (line_info_->LineEndFragment()) { - const NGPhysicalSize& size = line_info_->LineEndFragment()->Size(); + if (line_info->LineEndFragment()) { + const NGPhysicalSize& size = line_info->LineEndFragment()->Size(); position_ -= is_horizontal ? size.width : size.height; } if (fragment) { const NGPhysicalSize& size = fragment->Size(); position_ += is_horizontal ? size.width : size.height; } - line_info_->SetLineEndFragment(std::move(fragment)); -} - -inline void NGLineBreaker::ComputeCanBreakAfter( - NGInlineItemResult* item_result) const { - item_result->can_break_after = - auto_wrap_ && break_iterator_.IsBreakable(item_result->end_offset); + line_info->SetLineEndFragment(std::move(fragment)); } // Compute the base direction for bidi algorithm for this line. @@ -195,10 +240,11 @@ } // Initialize internal states for the next line. -void NGLineBreaker::PrepareNextLine() { +void NGLineBreaker::PrepareNextLine(NGLineInfo* line_info) { // NGLineInfo is not supposed to be re-used becase it's not much gain and to // avoid rare code path. - DCHECK(item_results_->IsEmpty()); + NGInlineItemResults* item_results = line_info->MutableResults(); + DCHECK(item_results->IsEmpty()); if (item_index_) { // We're past the first line @@ -208,44 +254,51 @@ use_first_line_style_ = false; } - line_info_->SetStartOffset(offset_); - line_info_->SetLineStyle(node_, items_data_, use_first_line_style_); + line_info->SetStartOffset(offset_); + line_info->SetLineStyle(node_, items_data_, use_first_line_style_); - DCHECK(!line_info_->TextIndent()); - if (line_info_->LineStyle().ShouldUseTextIndent( + DCHECK(!line_info->TextIndent()); + if (line_info->LineStyle().ShouldUseTextIndent( is_first_formatted_line_, previous_line_had_forced_break_)) { - const Length& length = line_info_->LineStyle().TextIndent(); + const Length& length = line_info->LineStyle().TextIndent(); LayoutUnit maximum_value; // Ignore percentages (resolve to 0) when calculating min/max intrinsic // sizes. if (length.IsPercentOrCalc() && mode_ == NGLineBreakerMode::kContent) maximum_value = constraint_space_.AvailableSize().inline_size; - line_info_->SetTextIndent(MinimumValueForLength(length, maximum_value)); + line_info->SetTextIndent(MinimumValueForLength(length, maximum_value)); } // Set the initial style of this line from the break token. Example: // <p>...<span>....</span></p> // When the line wraps in <span>, the 2nd line needs to start with the style // of the <span>. - SetCurrentStyle(current_style_ ? *current_style_ : line_info_->LineStyle()); + SetCurrentStyle(current_style_ ? *current_style_ : line_info->LineStyle()); ComputeBaseDirection(); - line_info_->SetBaseDirection(base_direction_); + line_info->SetBaseDirection(base_direction_); // Use 'text-indent' as the initial position. This lets tab positions to align // regardless of 'text-indent'. - position_ = line_info_->TextIndent(); + position_ = line_info->TextIndent(); } -void NGLineBreaker::NextLine(NGLineInfo* line_info) { - line_info_ = line_info; - item_results_ = line_info->MutableResults(); +void NGLineBreaker::NextLine( + LayoutUnit percentage_resolution_block_size_for_min_max, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo* line_info) { + // out_floats_for_min_max is required for min/max and prohibited for regular + // content mode. + DCHECK(mode_ == NGLineBreakerMode::kContent || out_floats_for_min_max); + DCHECK(!(mode_ == NGLineBreakerMode::kContent && out_floats_for_min_max)); - PrepareNextLine(); - BreakLine(); - RemoveTrailingCollapsibleSpace(); + PrepareNextLine(line_info); + BreakLine(percentage_resolution_block_size_for_min_max, + out_floats_for_min_max, line_info); + RemoveTrailingCollapsibleSpace(line_info); + NGInlineItemResults* item_results = line_info->MutableResults(); #if DCHECK_IS_ON() - for (const auto& result : *item_results_) + for (const auto& result : *item_results) result.CheckConsistency(mode_ == NGLineBreakerMode::kMinContent); #endif @@ -257,25 +310,24 @@ // // TODO(kojii): There are cases where we need to PlaceItems() without creating // line boxes. These cases need to be reviewed. - bool should_create_line_box = - ShouldCreateLineBox(*item_results_) || - (has_list_marker_ && line_info_->IsLastLine()) || - mode_ != NGLineBreakerMode::kContent; + bool should_create_line_box = ShouldCreateLineBox(*item_results) || + (has_list_marker_ && line_info->IsLastLine()) || + mode_ != NGLineBreakerMode::kContent; if (!should_create_line_box) - line_info_->SetIsEmptyLine(); - line_info_->SetEndItemIndex(item_index_); + line_info->SetIsEmptyLine(); + line_info->SetEndItemIndex(item_index_); DCHECK_NE(trailing_whitespace_, WhitespaceState::kUnknown); if (trailing_whitespace_ == WhitespaceState::kPreserved) - line_info_->SetHasTrailingSpaces(); + line_info->SetHasTrailingSpaces(); - ComputeLineLocation(); - - line_info_ = nullptr; - item_results_ = nullptr; + ComputeLineLocation(line_info); } -void NGLineBreaker::BreakLine() { +void NGLineBreaker::BreakLine( + LayoutUnit percentage_resolution_block_size_for_min_max, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo* line_info) { const Vector<NGInlineItem>& items = Items(); state_ = LineBreakState::kContinue; trailing_whitespace_ = WhitespaceState::kLeading; @@ -285,78 +337,82 @@ // |HandleOverflow| will rewind |item_index_|. if (state_ == LineBreakState::kContinue && position_ > AvailableWidthToFit()) { - HandleOverflow(); + HandleOverflow(line_info); } // If we reach at the end of the block, this is the last line. DCHECK_LE(item_index_, items.size()); if (item_index_ == items.size()) { - line_info_->SetIsLastLine(true); + line_info->SetIsLastLine(true); return; } + NGInlineItemResults* item_results = line_info->MutableResults(); + // Handle trailable items first. These items may not be break before. // They (or part of them) may also overhang the available width. const NGInlineItem& item = items[item_index_]; if (item.Type() == NGInlineItem::kText) { - HandleText(item); + HandleText(item, line_info); #if DCHECK_IS_ON() - if (!item_results_->IsEmpty()) - item_results_->back().CheckConsistency(true); + if (!item_results->IsEmpty()) + item_results->back().CheckConsistency(true); #endif continue; } if (item.Type() == NGInlineItem::kCloseTag) { - HandleCloseTag(item); + HandleCloseTag(item, line_info); continue; } if (item.Type() == NGInlineItem::kControl) { - HandleControlItem(item); + HandleControlItem(item, line_info); continue; } if (item.Type() == NGInlineItem::kFloating) { - HandleFloat(item); + HandleFloat(item, out_floats_for_min_max, line_info); continue; } if (item.Type() == NGInlineItem::kBidiControl) { - HandleBidiControlItem(item); + HandleBidiControlItem(item, line_info); continue; } // Items after this point are not trailable. Break at the earliest break // opportunity if we're trailing. if (state_ == LineBreakState::kTrailing && - CanBreakAfterLast(*item_results_)) { + CanBreakAfterLast(*item_results)) { if (sticky_images_quirk_ && IsImage(item) && (trailing_whitespace_ == WhitespaceState::kNone || trailing_whitespace_ == WhitespaceState::kUnknown)) { // If this is an image that follows text that doesn't end with something // breakable, we cannot break between the two items. - HandleAtomicInline(item); + HandleAtomicInline(item, percentage_resolution_block_size_for_min_max, + line_info); continue; } - line_info_->SetIsLastLine(false); + line_info->SetIsLastLine(false); return; } if (item.Type() == NGInlineItem::kAtomicInline) { - HandleAtomicInline(item); + HandleAtomicInline(item, percentage_resolution_block_size_for_min_max, + line_info); } else if (item.Type() == NGInlineItem::kOpenTag) { - HandleOpenTag(item); + HandleOpenTag(item, line_info); } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) { - AddItem(item); + AddItem(item, line_info); MoveToNextOf(item); } else if (item.Length()) { NOTREACHED(); // For other items with text (e.g., bidi controls), use their text to // determine the break opportunity. - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->can_break_after = break_iterator_.IsBreakable(item_result->end_offset); MoveToNextOf(item); } else if (item.Type() == NGInlineItem::kListMarker) { - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); has_list_marker_ = true; DCHECK(!item_result->can_break_after); MoveToNextOf(item); @@ -367,49 +423,36 @@ } } -// Re-compute the current position from NGLineInfo. -// The current position is usually updated as NGLineBreaker builds -// NGInlineItemResults. This function re-computes it when it was lost. -void NGLineBreaker::UpdatePosition() { - position_ = line_info_->ComputeWidth(); -} - -void NGLineBreaker::ComputeLineLocation() const { +void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const { // Negative margins can make the position negative, but the inline size is // always positive or 0. LayoutUnit available_width = AvailableWidth(); - DCHECK_EQ(position_, line_info_->ComputeWidth()); + DCHECK_EQ(position_, line_info->ComputeWidth()); - line_info_->SetWidth(available_width, position_); - line_info_->SetBfcOffset( + line_info->SetWidth(available_width, position_); + line_info->SetBfcOffset( {line_opportunity_.line_left_offset, line_opportunity_.bfc_block_offset}); } -void NGLineBreaker::HandleText(const NGInlineItem& item) { - DCHECK_EQ(item.Type(), NGInlineItem::kText); - DCHECK(item.TextShapeResult()); - HandleText(item, *item.TextShapeResult()); -} - void NGLineBreaker::HandleText(const NGInlineItem& item, - const ShapeResult& shape_result) { + const ShapeResult& shape_result, + NGLineInfo* line_info) { DCHECK(item.Type() == NGInlineItem::kText || (item.Type() == NGInlineItem::kControl && Text()[item.StartOffset()] == kTabulationCharacter)); - DCHECK(&shape_result); DCHECK_EQ(auto_wrap_, item.Style()->AutoWrap()); // If we're trailing, only trailing spaces can be included in this line. if (state_ == LineBreakState::kTrailing) { - if (CanBreakAfterLast(*item_results_)) - return HandleTrailingSpaces(item, shape_result); + if (CanBreakAfterLast(*line_info->MutableResults())) + return HandleTrailingSpaces(item, shape_result, line_info); // When a run of preserved spaces are across items, |CanBreakAfterLast| is // false for between spaces. But we still need to handle them as trailing // spaces. const String& text = Text(); if (auto_wrap_ && offset_ < text.length() && IsBreakableSpace(text[offset_])) - return HandleTrailingSpaces(item, shape_result); + return HandleTrailingSpaces(item, shape_result, line_info); } // Skip leading collapsible spaces. @@ -430,18 +473,20 @@ // |trailing_whitespace_| will be updated as we read the text. } - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->should_create_line_box = true; if (auto_wrap_) { if (mode_ == NGLineBreakerMode::kMinContent && - HandleTextForFastMinContent(item_result, item, shape_result)) { + HandleTextForFastMinContent(item_result, item, shape_result, + line_info)) { return; } // Try to break inside of this text item. LayoutUnit available_width = AvailableWidthToFit(); - BreakText(item_result, item, shape_result, available_width - position_); + BreakText(item_result, item, shape_result, available_width - position_, + line_info); if (item.IsSymbolMarker()) { LayoutUnit symbol_width = LayoutListMarker::WidthOfSymbol(*item.Style()); @@ -461,7 +506,7 @@ if (item_result->end_offset < item.EndOffset()) { // The break point found, and text follows. Break here, after trailing // spaces. - return HandleTrailingSpaces(item, shape_result); + return HandleTrailingSpaces(item, shape_result, line_info); } // The break point found, but items that prohibit breaking before them may @@ -469,7 +514,7 @@ return; } - return HandleOverflow(); + return HandleOverflow(line_info); } // Add the whole item if !auto_wrap. The previous line should not have wrapped @@ -494,16 +539,9 @@ void NGLineBreaker::BreakText(NGInlineItemResult* item_result, const NGInlineItem& item, - LayoutUnit available_width) { - DCHECK_EQ(item.Type(), NGInlineItem::kText); - DCHECK(item.TextShapeResult()); - BreakText(item_result, item, *item.TextShapeResult(), available_width); -} - -void NGLineBreaker::BreakText(NGInlineItemResult* item_result, - const NGInlineItem& item, const ShapeResult& item_shape_result, - LayoutUnit available_width) { + LayoutUnit available_width, + NGLineInfo* line_info) { DCHECK(item.Type() == NGInlineItem::kText || (item.Type() == NGInlineItem::kControl && Text()[item.StartOffset()] == kTabulationCharacter)); @@ -537,13 +575,13 @@ // Use kStartShouldBeSafe if at the beginning of a line. unsigned options = ShapingLineBreaker::kDefaultOptions; - if (item_result->start_offset != line_info_->StartOffset()) + if (item_result->start_offset != line_info->StartOffset()) options |= ShapingLineBreaker::kDontReshapeStart; // Reshaping between the last character and trailing spaces is needed only // when we need accurate end position, because kerning between trailing spaces // is not visible. - if (!NeedsAccurateEndPosition(*line_info_, item)) + if (!NeedsAccurateEndPosition(*line_info, item)) options |= ShapingLineBreaker::kDontReshapeEndIfAtSpace; // Use kNoResultIfOverflow if 'break-word' and we're trying to break normally @@ -568,7 +606,10 @@ result.break_offset - item_result->start_offset); if (result.is_hyphenated) { - AppendHyphen(item); + SetLineEndFragment( + CreateHyphenFragment(node_, constraint_space_.GetWritingMode(), item), + line_info); + // TODO(kojii): Implement when adding a hyphen caused overflow. // crbug.com/714962: Should be removed when switched to NGPaint. item_result->text_end_effect = NGTextEndEffect::kHyphen; @@ -619,10 +660,10 @@ // The first word and the last word, "1" and "6" in the example above, are // handled in normal |HandleText()| because they may form a word with the // previous/next item. -bool NGLineBreaker::HandleTextForFastMinContent( - NGInlineItemResult* item_result, - const NGInlineItem& item, - const ShapeResult& shape_result) { +bool NGLineBreaker::HandleTextForFastMinContent(NGInlineItemResult* item_result, + const NGInlineItem& item, + const ShapeResult& shape_result, + NGLineInfo* line_info) { DCHECK_EQ(mode_, NGLineBreakerMode::kMinContent); DCHECK(auto_wrap_); DCHECK(item.Type() == NGInlineItem::kText || @@ -634,7 +675,7 @@ // item. Fallback to |HandleText()|. unsigned start_offset = item_result->start_offset; DCHECK_LT(start_offset, item.EndOffset()); - if (start_offset != line_info_->StartOffset() && + if (start_offset != line_info->StartOffset() && start_offset == item.StartOffset()) return false; // If this is the last part of the text, it may form a word with the next @@ -730,6 +771,7 @@ // Compute a new ShapeResult for the specified end offset. // The end is re-shaped if it is not safe-to-break. scoped_refptr<ShapeResultView> NGLineBreaker::TruncateLineEndResult( + const NGLineInfo& line_info, const NGInlineItemResult& item_result, unsigned end_offset) { DCHECK(item_result.item); @@ -744,7 +786,7 @@ DCHECK(start_offset > source_result->StartIndex() || end_offset < source_result->EndIndex()); - if (!NeedsAccurateEndPosition(*line_info_, item)) { + if (!NeedsAccurateEndPosition(line_info, item)) { return ShapeResultView::Create(source_result, start_offset, end_offset); } @@ -765,16 +807,18 @@ // Update |ShapeResult| in |item_result| to match to its |start_offset| and // |end_offset|. The end is re-shaped if it is not safe-to-break. -void NGLineBreaker::UpdateShapeResult(NGInlineItemResult* item_result) { +void NGLineBreaker::UpdateShapeResult(const NGLineInfo& line_info, + NGInlineItemResult* item_result) { DCHECK(item_result); item_result->shape_result = - TruncateLineEndResult(*item_result, item_result->end_offset); + TruncateLineEndResult(line_info, *item_result, item_result->end_offset); DCHECK(item_result->shape_result); item_result->inline_size = item_result->shape_result->SnappedWidth(); } void NGLineBreaker::HandleTrailingSpaces(const NGInlineItem& item, - const ShapeResult& shape_result) { + const ShapeResult& shape_result, + NGLineInfo* line_info) { DCHECK(item.Type() == NGInlineItem::kText || (item.Type() == NGInlineItem::kControl && Text()[item.StartOffset()] == kTabulationCharacter)); @@ -801,8 +845,9 @@ trailing_whitespace_ = WhitespaceState::kCollapsed; // Make the last item breakable after, even if it was nowrap. - DCHECK(!item_results_->IsEmpty()); - item_results_->back().can_break_after = true; + NGInlineItemResults* item_results = line_info->MutableResults(); + DCHECK(!item_results->IsEmpty()); + item_results->back().can_break_after = true; } else { // Find the end of the run of space characters in this item. // Other white space characters (e.g., tab) are not included in this item. @@ -815,14 +860,14 @@ return; } - NGInlineItemResult* item_result = AddItem(item, end); + NGInlineItemResult* item_result = AddItem(item, end, line_info); item_result->has_only_trailing_spaces = true; item_result->shape_result = ShapeResultView::Create(&shape_result); if (item_result->start_offset == item.StartOffset() && item_result->end_offset == item.EndOffset()) item_result->inline_size = item_result->shape_result->SnappedWidth(); else - UpdateShapeResult(item_result); + UpdateShapeResult(*line_info, item_result); position_ += item_result->inline_size; item_result->can_break_after = end < text.length() && !IsBreakableSpace(text[end]); @@ -843,8 +888,8 @@ // Remove trailing collapsible spaces in |line_info|. // https://drafts.csswg.org/css-text-3/#white-space-phase-2 -void NGLineBreaker::RemoveTrailingCollapsibleSpace() { - ComputeTrailingCollapsibleSpace(); +void NGLineBreaker::RemoveTrailingCollapsibleSpace(NGLineInfo* line_info) { + ComputeTrailingCollapsibleSpace(line_info); if (!trailing_collapsible_space_.has_value()) { return; } @@ -860,15 +905,15 @@ item_result->inline_size = item_result->shape_result->SnappedWidth(); position_ += item_result->inline_size; } else { - item_results_->erase(item_result); + line_info->MutableResults()->erase(item_result); } trailing_collapsible_space_.reset(); trailing_whitespace_ = WhitespaceState::kCollapsed; } // Compute the width of trailing spaces without removing it. -LayoutUnit NGLineBreaker::TrailingCollapsibleSpaceWidth() { - ComputeTrailingCollapsibleSpace(); +LayoutUnit NGLineBreaker::TrailingCollapsibleSpaceWidth(NGLineInfo* line_info) { + ComputeTrailingCollapsibleSpace(line_info); if (!trailing_collapsible_space_.has_value()) return LayoutUnit(); @@ -884,7 +929,7 @@ // Find trailing collapsible space if exists. The result is cached to // |trailing_collapsible_space_|. -void NGLineBreaker::ComputeTrailingCollapsibleSpace() { +void NGLineBreaker::ComputeTrailingCollapsibleSpace(NGLineInfo* line_info) { if (trailing_whitespace_ == WhitespaceState::kLeading || trailing_whitespace_ == WhitespaceState::kNone || trailing_whitespace_ == WhitespaceState::kCollapsed || @@ -897,7 +942,8 @@ trailing_whitespace_ = WhitespaceState::kNone; const String& text = Text(); - for (auto it = item_results_->rbegin(); it != item_results_->rend(); ++it) { + NGInlineItemResults* item_results = line_info->MutableResults(); + for (auto it = item_results->rbegin(); it != item_results->rend(); ++it) { NGInlineItemResult& item_result = *it; DCHECK(item_result.item); const NGInlineItem& item = *item_result.item; @@ -923,7 +969,8 @@ trailing_collapsible_space_->item_result = &item_result; if (item_result.end_offset - 1 > item_result.start_offset) { trailing_collapsible_space_->collapsed_shape_result = - TruncateLineEndResult(item_result, item_result.end_offset - 1); + TruncateLineEndResult(*line_info, item_result, + item_result.end_offset - 1); } } trailing_whitespace_ = WhitespaceState::kCollapsible; @@ -943,33 +990,19 @@ trailing_collapsible_space_.reset(); } -void NGLineBreaker::AppendHyphen(const NGInlineItem& item) { - DCHECK(item.Style()); - const ComputedStyle& style = *item.Style(); - TextDirection direction = style.Direction(); - String hyphen_string = style.HyphenString(); - HarfBuzzShaper shaper(hyphen_string); - scoped_refptr<ShapeResult> hyphen_result = - shaper.Shape(&style.GetFont(), direction); - NGTextFragmentBuilder builder(node_, constraint_space_.GetWritingMode()); - builder.SetText(item.GetLayoutObject(), hyphen_string, &style, - /* is_ellipsis_style */ false, - ShapeResultView::Create(hyphen_result.get())); - SetLineEndFragment(builder.ToTextFragment()); -} - // Measure control items; new lines and tab, that are similar to text, affect // layout, but do not need shaping/painting. -void NGLineBreaker::HandleControlItem(const NGInlineItem& item) { +void NGLineBreaker::HandleControlItem(const NGInlineItem& item, + NGLineInfo* line_info) { DCHECK_GE(item.Length(), 1u); UChar character = Text()[item.StartOffset()]; switch (character) { case kNewlineCharacter: { - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->should_create_line_box = true; item_result->has_only_trailing_spaces = true; is_after_forced_break_ = true; - line_info_->SetIsLastLine(true); + line_info->SetIsLastLine(true); state_ = LineBreakState::kDone; break; } @@ -980,12 +1013,12 @@ ShapeResult::CreateForTabulationCharacters( &style.GetFont(), item.Direction(), style.GetTabSize(), position_, item.StartOffset(), item.Length()); - HandleText(item, *shape_result); + HandleText(item, *shape_result, line_info); return; } case kZeroWidthSpaceCharacter: { // <wbr> tag creates break opportunities regardless of auto_wrap. - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->should_create_line_box = true; item_result->can_break_after = true; break; @@ -1003,7 +1036,8 @@ MoveToNextOf(item); } -void NGLineBreaker::HandleBidiControlItem(const NGInlineItem& item) { +void NGLineBreaker::HandleBidiControlItem(const NGInlineItem& item, + NGLineInfo* line_info) { DCHECK_EQ(item.Length(), 1u); // Bidi control characters have enter/exit semantics. Handle "enter" @@ -1012,33 +1046,37 @@ UChar character = Text()[item.StartOffset()]; bool is_pop = character == kPopDirectionalIsolateCharacter || character == kPopDirectionalFormattingCharacter; + NGInlineItemResults* item_results = line_info->MutableResults(); if (is_pop) { - if (!item_results_->IsEmpty()) { - NGInlineItemResult* item_result = AddItem(item); - NGInlineItemResult* last = &(*item_results_)[item_results_->size() - 2]; + if (!item_results->IsEmpty()) { + NGInlineItemResult* item_result = AddItem(item, line_info); + NGInlineItemResult* last = &(*item_results)[item_results->size() - 2]; item_result->can_break_after = last->can_break_after; last->can_break_after = false; } else { - AddItem(item); + AddItem(item, line_info); } } else { if (state_ == LineBreakState::kTrailing && - CanBreakAfterLast(*item_results_)) { - line_info_->SetIsLastLine(false); + CanBreakAfterLast(*item_results)) { + line_info->SetIsLastLine(false); MoveToNextOf(item); state_ = LineBreakState::kDone; return; } - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); DCHECK(!item_result->can_break_after); } MoveToNextOf(item); } -void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item) { +void NGLineBreaker::HandleAtomicInline( + const NGInlineItem& item, + LayoutUnit percentage_resolution_block_size_for_min_max, + NGLineInfo* line_info) { DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); - NGInlineItemResult* item_result = AddItem(item); + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->should_create_line_box = true; // When we're just computing min/max content sizes, we can skip the full // layout and just compute those sizes. On the other hand, for regular @@ -1049,8 +1087,8 @@ item_result->layout_result = NGBlockNode(ToLayoutBox(item.GetLayoutObject())) .LayoutAtomicInline(constraint_space_, node_.Style(), - line_info_->LineStyle().GetFontBaseline(), - line_info_->UseFirstLineStyle()); + line_info->LineStyle().GetFontBaseline(), + line_info->UseFirstLineStyle()); DCHECK(item_result->layout_result->PhysicalFragment()); item_result->inline_size = @@ -1059,7 +1097,7 @@ .InlineSize(); } else { NGBlockNode child(ToLayoutBox(item.GetLayoutObject())); - MinMaxSizeInput input(percentage_resolution_block_size_for_min_max_); + MinMaxSizeInput input(percentage_resolution_block_size_for_min_max); MinMaxSize sizes = ComputeMinAndMaxContentContribution(node_.Style(), child, input); item_result->inline_size = mode_ == NGLineBreakerMode::kMinContent @@ -1078,7 +1116,7 @@ trailing_whitespace_ = WhitespaceState::kNone; position_ += item_result->inline_size; - ComputeCanBreakAfter(item_result); + ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_); if (sticky_images_quirk_ && IsImage(item)) { const auto& items = Items(); @@ -1109,7 +1147,9 @@ // We have this check if there are already UnpositionedFloats as we aren't // allowed to position a float "above" another float which has come before us // in the document. -void NGLineBreaker::HandleFloat(const NGInlineItem& item) { +void NGLineBreaker::HandleFloat(const NGInlineItem& item, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo* line_info) { // When rewind occurs, an item may be handled multiple times. // Since floats are put into a separate list, avoid handling same floats // twice. @@ -1119,15 +1159,15 @@ // Additionally, we need to skip floats if we're retrying a line after a // fragmentainer break. In that case the floats associated with this line will // already have been processed. - NGInlineItemResult* item_result = AddItem(item); - ComputeCanBreakAfter(item_result); + NGInlineItemResult* item_result = AddItem(item, line_info); + ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_); MoveToNextOf(item); // If we are currently computing our min/max-content size simply append to // the unpositioned floats list and abort. if (mode_ != NGLineBreakerMode::kContent) { - DCHECK(out_floats_for_min_max_); - out_floats_for_min_max_->push_back(item.GetLayoutObject()); + DCHECK(out_floats_for_min_max); + out_floats_for_min_max->push_back(item.GetLayoutObject()); return; } @@ -1154,8 +1194,9 @@ LayoutUnit bfc_block_offset = line_opportunity_.bfc_block_offset; - LayoutUnit used_size = - position_ + inline_margin_size + ComputeFloatAncestorInlineEndSize(); + LayoutUnit used_size = position_ + inline_margin_size + + ComputeFloatAncestorInlineEndSize( + constraint_space_, Items(), item_index_); bool can_fit_float = used_size <= line_opportunity_.AvailableFloatInlineSize().AddEpsilon(); if (!can_fit_float) { @@ -1164,7 +1205,7 @@ // removed if this line breaks here because they should be collapsed across // floats, but they are still included in the current line position at this // point. Exclude it when computing whether this float can fit or not. - can_fit_float = used_size - TrailingCollapsibleSpaceWidth() <= + can_fit_float = used_size - TrailingCollapsibleSpaceWidth(line_info) <= line_opportunity_.AvailableFloatInlineSize().AddEpsilon(); } @@ -1181,7 +1222,7 @@ // Check if we already have a pending float. That's because a float cannot be // higher than any block or floated box generated before. - if (HasUnpositionedFloats(*item_results_) || float_after_line) { + if (HasUnpositionedFloats(*line_info->MutableResults()) || float_after_line) { item_result->has_unpositioned_floats = true; } else { NGPositionedFloat positioned_float = PositionFloat( @@ -1207,39 +1248,6 @@ } } -// To correctly determine if a float is allowed to be on the same line as its -// content, we need to determine if it has any ancestors with inline-end -// padding, border, or margin. -// The inline-end size from all of these ancestors contribute to the "used -// size" of the float, and may cause the float to be pushed down. -LayoutUnit NGLineBreaker::ComputeFloatAncestorInlineEndSize() const { - const Vector<NGInlineItem>& items = Items(); - wtf_size_t item_index = item_index_; - - LayoutUnit inline_end_size; - while (item_index < items.size()) { - const NGInlineItem& item = items[item_index++]; - - if (item.Type() == NGInlineItem::kCloseTag) { - if (item.HasEndEdge()) { - inline_end_size += - ComputeInlineEndSize(constraint_space_, item.Style()); - } - continue; - } - - // For this calculation, any open tag (even if its empty) stops this - // calculation, and allows the float to appear on the same line. E.g. - // <span style="padding-right: 20px;"><f></f><span></span></span> - // - // Any non-empty item also allows the float to be on the same line. - if (item.Type() == NGInlineItem::kOpenTag || !item.IsEmptyItem()) - break; - } - - return inline_end_size; -} - bool NGLineBreaker::ComputeOpenTagResult( const NGInlineItem& item, const NGConstraintSpace& constraint_space, @@ -1264,8 +1272,9 @@ return false; } -void NGLineBreaker::HandleOpenTag(const NGInlineItem& item) { - NGInlineItemResult* item_result = AddItem(item); +void NGLineBreaker::HandleOpenTag(const NGInlineItem& item, + NGLineInfo* line_info) { + NGInlineItemResult* item_result = AddItem(item, line_info); if (ComputeOpenTagResult(item, constraint_space_, item_result)) { position_ += item_result->inline_size; @@ -1285,13 +1294,15 @@ MoveToNextOf(item); DCHECK(!item_result->can_break_after); - if (UNLIKELY(!was_auto_wrap && auto_wrap_ && item_results_->size() >= 2)) { - ComputeCanBreakAfter(std::prev(item_result)); + NGInlineItemResults* item_results = line_info->MutableResults(); + if (UNLIKELY(!was_auto_wrap && auto_wrap_ && item_results->size() >= 2)) { + ComputeCanBreakAfter(std::prev(item_result), auto_wrap_, break_iterator_); } } -void NGLineBreaker::HandleCloseTag(const NGInlineItem& item) { - NGInlineItemResult* item_result = AddItem(item); +void NGLineBreaker::HandleCloseTag(const NGInlineItem& item, + NGLineInfo* line_info) { + NGInlineItemResult* item_result = AddItem(item, line_info); item_result->has_edge = item.HasEndEdge(); if (item_result->has_edge) { @@ -1310,7 +1321,8 @@ // If the line can break after the previous item, prohibit it and allow break // after this close tag instead. if (was_auto_wrap) { - if (item_results_->size() >= 2) { + NGInlineItemResults* item_results = line_info->MutableResults(); + if (item_results->size() >= 2) { NGInlineItemResult* last = std::prev(item_result); item_result->can_break_after = last->can_break_after; last->can_break_after = false; @@ -1332,13 +1344,13 @@ item_result->can_break_after = true; return; } - ComputeCanBreakAfter(item_result); + ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_); } // Handles when the last item overflows. // At this point, item_results does not fit into the current line, and there // are no break opportunities in item_results.back(). -void NGLineBreaker::HandleOverflow() { +void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) { // Compute the width needing to rewind. When |width_to_rewind| goes negative, // items can fit within the line. LayoutUnit available_width = AvailableWidthToFit(); @@ -1355,14 +1367,15 @@ bool has_break_anywhere_if_overflow = break_anywhere_if_overflow_; // Search for a break opportunity that can fit. - for (unsigned i = item_results_->size(); i;) { - NGInlineItemResult* item_result = &(*item_results_)[--i]; + NGInlineItemResults* item_results = line_info->MutableResults(); + for (unsigned i = item_results->size(); i;) { + NGInlineItemResult* item_result = &(*item_results)[--i]; // Try to break after this item. - if (i < item_results_->size() - 1 && item_result->can_break_after) { + if (i < item_results->size() - 1 && item_result->can_break_after) { if (width_to_rewind <= 0) { position_ = available_width + width_to_rewind; - Rewind(i + 1); + Rewind(i + 1, line_info); state_ = LineBreakState::kTrailing; return; } @@ -1383,7 +1396,8 @@ LayoutUnit item_available_width = std::min(-width_to_rewind, item_result->inline_size - 1); SetCurrentStyle(*item.Style()); - BreakText(item_result, item, item_available_width); + BreakText(item_result, item, *item.TextShapeResult(), + item_available_width, line_info); #if DCHECK_IS_ON() item_result->CheckConsistency(true); #endif @@ -1391,19 +1405,19 @@ if (item_result->inline_size <= item_available_width) { DCHECK(item_result->end_offset < item.EndOffset()); DCHECK(item_result->can_break_after); - DCHECK_LE(i + 1, item_results_->size()); - if (i + 1 == item_results_->size()) { + DCHECK_LE(i + 1, item_results->size()); + if (i + 1 == item_results->size()) { // If this is the last item, adjust states to accomodate the change. position_ = available_width + width_to_rewind + item_result->inline_size; - if (line_info_->LineEndFragment()) - SetLineEndFragment(nullptr); - DCHECK_EQ(position_, line_info_->ComputeWidth()); + if (line_info->LineEndFragment()) + SetLineEndFragment(nullptr, line_info); + DCHECK_EQ(position_, line_info->ComputeWidth()); item_index_ = item_result->item_index; offset_ = item_result->end_offset; items_data_.AssertOffset(item_index_, offset_); } else { - Rewind(i + 1); + Rewind(i + 1, line_info); } state_ = LineBreakState::kTrailing; return; @@ -1422,32 +1436,32 @@ break_iterator_.SetBreakType(LineBreakType::kBreakCharacter); // TODO(kojii): Not all items need to rewind, but such case is rare and // rewinding all items simplifes the code. - if (!item_results_->IsEmpty()) - Rewind(0); + if (!item_results->IsEmpty()) + Rewind(0, line_info); state_ = LineBreakState::kContinue; return; } // Let this line overflow. - line_info_->SetHasOverflow(); + line_info->SetHasOverflow(); // If there was a break opportunity, the overflow should stop there. if (break_before) { - Rewind(break_before); + Rewind(break_before, line_info); state_ = LineBreakState::kTrailing; return; } if (position_maybe_changed) { trailing_whitespace_ = WhitespaceState::kUnknown; - UpdatePosition(); + position_ = line_info->ComputeWidth(); } state_ = LineBreakState::kTrailing; } -void NGLineBreaker::Rewind(unsigned new_end) { - NGInlineItemResults& item_results = *item_results_; +void NGLineBreaker::Rewind(unsigned new_end, NGLineInfo* line_info) { + NGInlineItemResults& item_results = *line_info->MutableResults(); DCHECK_LT(new_end, item_results.size()); // Avoid rewinding floats if possible. They will be added back anyway while @@ -1457,7 +1471,7 @@ while (item_results[new_end].item->Type() == NGInlineItem::kFloating) { ++new_end; if (new_end == item_results.size()) { - UpdatePosition(); + position_ = line_info->ComputeWidth(); return; } } @@ -1473,7 +1487,7 @@ // still better than rewinding them. new_end = i + 1; if (new_end == item_results.size()) { - UpdatePosition(); + position_ = line_info->ComputeWidth(); return; } break; @@ -1492,21 +1506,22 @@ offset_ = first_remove.start_offset; trailing_whitespace_ = WhitespaceState::kLeading; } - SetCurrentStyle(ComputeCurrentStyle(new_end)); + SetCurrentStyle(ComputeCurrentStyle(new_end, line_info)); item_results.Shrink(new_end); trailing_collapsible_space_.reset(); - SetLineEndFragment(nullptr); - UpdatePosition(); + SetLineEndFragment(nullptr, line_info); + position_ = line_info->ComputeWidth(); } // Returns the style to use for |item_result_index|. Normally when handling // items sequentially, the current style is updated on open/close tag. When // rewinding, this function computes the style for the specified item. const ComputedStyle& NGLineBreaker::ComputeCurrentStyle( - unsigned item_result_index) const { - NGInlineItemResults& item_results = *item_results_; + unsigned item_result_index, + NGLineInfo* line_info) const { + NGInlineItemResults& item_results = *line_info->MutableResults(); // Use the current item if it can compute the current style. const NGInlineItem* item = item_results[item_result_index].item; @@ -1534,7 +1549,7 @@ DCHECK(break_token_->Style()); return *break_token_->Style(); } - return line_info_->LineStyle(); + return line_info->LineStyle(); } void NGLineBreaker::SetCurrentStyle(const ComputedStyle& style) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h index 61fd33e..11e43be 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -39,15 +39,23 @@ const NGPositionedFloatVector& leading_floats, unsigned handled_leading_floats_index, const NGInlineBreakToken*, - NGExclusionSpace*, - LayoutUnit percentage_resolution_block_size_for_min_max = - NGSizeIndefinite, - Vector<LayoutObject*>* out_floats_for_min_max = nullptr); + NGExclusionSpace*); ~NGLineBreaker(); // Compute the next line break point and produces NGInlineItemResults for // the line. - void NextLine(NGLineInfo*); + inline void NextLine(NGLineInfo* line_info) { + NextLine(NGSizeIndefinite, nullptr, line_info); + } + + // During the min/max size calculation we need a special percentage + // resolution block-size to pass to children/pass to children. + // TODO(layout-dev): Split into two methods (NextLine/NextLineForMinMax) or, + // better yet, subclass or templetize the line-breaker for Min/Max computation + // if we can do that without incurring a performance penalty + void NextLine(LayoutUnit percentage_resolution_block_size_for_min_max, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo*); bool IsFinished() const { return item_index_ >= Items().size(); } @@ -78,17 +86,19 @@ const String& Text() const { return items_data_.text_content; } const Vector<NGInlineItem>& Items() const { return items_data_.items; } - NGInlineItemResult* AddItem(const NGInlineItem&, unsigned end_offset); - NGInlineItemResult* AddItem(const NGInlineItem&); - void SetLineEndFragment(scoped_refptr<const NGPhysicalTextFragment>); - void ComputeCanBreakAfter(NGInlineItemResult*) const; + NGInlineItemResult* AddItem(const NGInlineItem&, + unsigned end_offset, + NGLineInfo*); + NGInlineItemResult* AddItem(const NGInlineItem&, NGLineInfo*); + void SetLineEndFragment(scoped_refptr<const NGPhysicalTextFragment>, + NGLineInfo*); - void BreakLine(); + void BreakLine(LayoutUnit percentage_resolution_block_size_for_min_max, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo*); + void PrepareNextLine(NGLineInfo*); - void PrepareNextLine(); - - void UpdatePosition(); - void ComputeLineLocation() const; + void ComputeLineLocation(NGLineInfo*) const; enum class LineBreakState { // The line breaking is complete. @@ -103,49 +113,55 @@ kContinue, }; - void HandleText(const NGInlineItem&); - void HandleText(const NGInlineItem&, const ShapeResult& shape_result); + inline void HandleText(const NGInlineItem& item, NGLineInfo* line_info) { + DCHECK(item.TextShapeResult()); + HandleText(item, *item.TextShapeResult(), line_info); + } + void HandleText(const NGInlineItem& item, const ShapeResult&, NGLineInfo*); void BreakText(NGInlineItemResult*, const NGInlineItem&, - LayoutUnit available_width); - void BreakText(NGInlineItemResult*, - const NGInlineItem&, - const ShapeResult& shape_result, - LayoutUnit available_width); - bool HandleTextForFastMinContent(NGInlineItemResult* item_result, - const NGInlineItem& item, - const ShapeResult& shape_result); + const ShapeResult&, + LayoutUnit available_width, + NGLineInfo*); + bool HandleTextForFastMinContent(NGInlineItemResult*, + const NGInlineItem&, + const ShapeResult&, + NGLineInfo*); scoped_refptr<ShapeResultView> TruncateLineEndResult( - const NGInlineItemResult& item_result, + const NGLineInfo&, + const NGInlineItemResult&, unsigned end_offset); - void UpdateShapeResult(NGInlineItemResult*); - scoped_refptr<ShapeResult> ShapeText(const NGInlineItem& item, + void UpdateShapeResult(const NGLineInfo&, NGInlineItemResult*); + scoped_refptr<ShapeResult> ShapeText(const NGInlineItem&, unsigned start, unsigned end); void HandleTrailingSpaces(const NGInlineItem&, - const ShapeResult& shape_result); - void RemoveTrailingCollapsibleSpace(); - LayoutUnit TrailingCollapsibleSpaceWidth(); - void ComputeTrailingCollapsibleSpace(); + const ShapeResult&, + NGLineInfo*); + void RemoveTrailingCollapsibleSpace(NGLineInfo*); + LayoutUnit TrailingCollapsibleSpaceWidth(NGLineInfo*); + void ComputeTrailingCollapsibleSpace(NGLineInfo*); - void AppendHyphen(const NGInlineItem& item); + void HandleControlItem(const NGInlineItem&, NGLineInfo*); + void HandleBidiControlItem(const NGInlineItem&, NGLineInfo*); + void HandleAtomicInline( + const NGInlineItem&, + LayoutUnit percentage_resolution_block_size_for_min_max, + NGLineInfo*); + void HandleFloat(const NGInlineItem&, + Vector<LayoutObject*>* out_floats_for_min_max, + NGLineInfo*); - void HandleControlItem(const NGInlineItem&); - void HandleBidiControlItem(const NGInlineItem&); - void HandleAtomicInline(const NGInlineItem&); - void HandleFloat(const NGInlineItem&); + void HandleOpenTag(const NGInlineItem&, NGLineInfo*); + void HandleCloseTag(const NGInlineItem&, NGLineInfo*); - LayoutUnit ComputeFloatAncestorInlineEndSize() const; + void HandleOverflow(NGLineInfo*); + void Rewind(unsigned new_end, NGLineInfo*); - void HandleOpenTag(const NGInlineItem&); - void HandleCloseTag(const NGInlineItem&); - - void HandleOverflow(); - void Rewind(unsigned new_end); - - const ComputedStyle& ComputeCurrentStyle(unsigned item_result_index) const; + const ComputedStyle& ComputeCurrentStyle(unsigned item_result_index, + NGLineInfo*) const; void SetCurrentStyle(const ComputedStyle&); void MoveToNextOf(const NGInlineItem&); @@ -160,12 +176,6 @@ return AvailableWidth().AddEpsilon(); } - // These fields are the output of the current line. - // NGInlineItemResults is a pointer because the move operation is not cheap - // due to its inline buffer. - NGLineInfo* line_info_ = nullptr; - NGInlineItemResults* item_results_ = nullptr; - // Represents the current offset of the input. LineBreakState state_; unsigned item_index_ = 0; @@ -255,11 +265,6 @@ // This is copied from NGInlineNode, then updated after each forced line break // if 'unicode-bidi: plaintext'. TextDirection base_direction_; - - // During the min/max size calculation we need a special percentage - // resolution block-size to pass to children/pass to children. - LayoutUnit percentage_resolution_block_size_for_min_max_; - Vector<LayoutObject*>* out_floats_for_min_max_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc index 330fe32..9ef582897 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
@@ -503,7 +503,7 @@ return PositionWithAffinity(GetLastPosition(position.index), TextAffinity::kDownstream); } - return PositionWithAffinity(GetLastPosition(position.index + 1), + return PositionWithAffinity(GetFirstPosition(position.index + 1), TextAffinity::kUpstream); }
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc index bd82b7d..aa1a1dc 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -141,7 +141,7 @@ scoped_refptr<const NGLayoutResult> result = container_builder.ToBoxFragment(); // These are the unpositioned OOF descendants of the current OOF block. - for (NGOutOfFlowPositionedDescendant descendant : + for (const NGOutOfFlowPositionedDescendant& descendant : result->OutOfFlowPositionedDescendants()) descendant.node.UseOldOutOfFlowPositioning();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h index e63405c..4982b14 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -138,7 +138,7 @@ } bool CreatesNewFormattingContext() const { - return IsBlock() && box_->AvoidsFloats(); + return IsBlock() && box_->CreatesNewFormattingContext(); } // Returns true if this node should pass its percentage resolution block-size
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index eeadd72..c197575 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -236,7 +236,7 @@ } void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks( - Vector<NGOutOfFlowPositionedDescendant> descendants) { + const Vector<NGOutOfFlowPositionedDescendant>& descendants) { NGBoxFragmentBuilder::InlineContainingBlockMap inline_container_fragments; for (auto& descendant : descendants) { @@ -391,7 +391,7 @@ } void NGOutOfFlowLayoutPart::LayoutDescendantCandidates( - const Vector<NGOutOfFlowPositionedDescendant> descendant_candidates, + const Vector<NGOutOfFlowPositionedDescendant>& descendant_candidates, const LayoutBox* only_layout, HashSet<const LayoutObject*>* placed_objects) { for (auto& candidate : descendant_candidates) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index 133c372..b167f31b9 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -93,10 +93,11 @@ ContainingBlockInfo GetContainingBlockInfo( const NGOutOfFlowPositionedDescendant&) const; - void ComputeInlineContainingBlocks(Vector<NGOutOfFlowPositionedDescendant>); + void ComputeInlineContainingBlocks( + const Vector<NGOutOfFlowPositionedDescendant>&); void LayoutDescendantCandidates( - const Vector<NGOutOfFlowPositionedDescendant> descendant_candidates, + const Vector<NGOutOfFlowPositionedDescendant>& descendant_candidates, const LayoutBox* only_layout, HashSet<const LayoutObject*>* placed_objects);
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index ab0914f..dc43e06 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -160,6 +160,7 @@ origin_policy_ = params_->origin_policy; requestor_origin_ = params_->requestor_origin; unreachable_url_ = params_->unreachable_url; + error_code_ = params_->error_code; previews_state_ = params_->previews_state; // See WebNavigationParams for special case explanations.
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h index 42acae7e..e6d63d54 100644 --- a/third_party/blink/renderer/core/loader/document_loader.h +++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -254,6 +254,8 @@ void ProvideDocumentToResourceFetcherProperties(Document&); + int ErrorCode() const { return error_code_; } + protected: bool had_transient_activation() const { return had_transient_activation_; } @@ -346,6 +348,7 @@ String origin_policy_; scoped_refptr<const SecurityOrigin> requestor_origin_; KURL unreachable_url_; + int error_code_; std::unique_ptr<WebNavigationBodyLoader> body_loader_; // Params are saved in constructor and are cleared after StartLoading().
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index 300738c..72affbe 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -893,8 +893,8 @@ ->ExperimentalFeaturesEnabled()) { initiator_csp = origin_document->GetContentSecurityPolicy() ->ExposeForNavigationalChecks(); - auto request = mojo::MakeRequest(&navigation_initiator); - origin_document->BindNavigationInitiatorRequest(std::move(request)); + auto mojo_request = mojo::MakeRequest(&navigation_initiator); + origin_document->BindNavigationInitiatorRequest(std::move(mojo_request)); } if (origin_document && origin_document->GetContentSecurityPolicy()) {
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc index 5ad345e1..40b84e1 100644 --- a/third_party/blink/renderer/core/page/create_window.cc +++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -424,6 +424,7 @@ // createWindow(LocalFrame& openerFrame, ...). // This value will be set in ResourceRequest loaded in a new LocalFrame. bool has_user_gesture = LocalFrame::HasTransientUserActivation(&opener_frame); + opener_frame.MaybeLogAdClickNavigation(); // We pass the opener frame for the lookupFrame in case the active frame is // different from the opener frame, and the name references a frame relative
diff --git a/third_party/blink/renderer/core/paint/BUILD.gn b/third_party/blink/renderer/core/paint/BUILD.gn index f95d1ebb0..13b93f65 100644 --- a/third_party/blink/renderer/core/paint/BUILD.gn +++ b/third_party/blink/renderer/core/paint/BUILD.gn
@@ -41,6 +41,8 @@ "collapsed_border_painter.h", "compositing/composited_layer_mapping.cc", "compositing/composited_layer_mapping.h", + "compositing/compositing_inputs_root.cc", + "compositing/compositing_inputs_root.h", "compositing/compositing_inputs_updater.cc", "compositing/compositing_inputs_updater.h", "compositing/compositing_layer_assigner.cc",
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc new file mode 100644 index 0000000..1086d93 --- /dev/null +++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.cc
@@ -0,0 +1,36 @@ +// Copyright 2019 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 "third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h" + +#include "third_party/blink/renderer/core/paint/paint_layer.h" + +namespace blink { + +void CompositingInputsRoot::Update(PaintLayer* new_root_layer) { + DCHECK(new_root_layer); + + if (!root_layer_) { + // This is the first time we call Update() so just let set the root layer. + root_layer_ = new_root_layer; + return; + } + + if (root_layer_ == new_root_layer) + return; + + PaintLayer* common_ancestor = + const_cast<PaintLayer*>(root_layer_->CommonAncestor(new_root_layer)); + if (!common_ancestor) + common_ancestor = const_cast<PaintLayer*>(root_layer_->Root()); + + root_layer_->SetChildNeedsCompositingInputsUpdateUpToAncestor( + common_ancestor); + new_root_layer->SetChildNeedsCompositingInputsUpdateUpToAncestor( + common_ancestor); + + root_layer_ = common_ancestor; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h new file mode 100644 index 0000000..896f3d48 --- /dev/null +++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h
@@ -0,0 +1,25 @@ +// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_ + +namespace blink { + +class PaintLayer; + +class CompositingInputsRoot { + public: + PaintLayer* Get() const { return root_layer_; } + + void Update(PaintLayer* new_root_layer); + void Clear() { root_layer_ = nullptr; } + + private: + PaintLayer* root_layer_ = nullptr; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_COMPOSITING_INPUTS_ROOT_H_
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc index 48bf5a3..16d6abf0 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -24,19 +24,50 @@ : clip_chain_parent->ClippingContainer(); } -CompositingInputsUpdater::CompositingInputsUpdater(PaintLayer* root_layer) - : geometry_map_(kUseTransforms), root_layer_(root_layer) {} +CompositingInputsUpdater::CompositingInputsUpdater( + PaintLayer* root_layer, + PaintLayer* compositing_inputs_root) + : geometry_map_(kUseTransforms), + root_layer_(root_layer), + compositing_inputs_root_(compositing_inputs_root) {} CompositingInputsUpdater::~CompositingInputsUpdater() = default; void CompositingInputsUpdater::Update() { TRACE_EVENT0("blink", "CompositingInputsUpdater::update"); - UpdateRecursive(root_layer_, kDoNotForceUpdate, AncestorInfo()); + + AncestorInfo info; + UpdateType update_type = kDoNotForceUpdate; + ApplyAncestorInfoToSelfAndAncestorsRecursively( + compositing_inputs_root_ ? compositing_inputs_root_ : root_layer_, + update_type, info); + + UpdateSelfAndDescendantsRecursively( + compositing_inputs_root_ ? compositing_inputs_root_ : root_layer_, + update_type, info); } -void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer, - UpdateType update_type, - AncestorInfo info) { +void CompositingInputsUpdater::ApplyAncestorInfoToSelfAndAncestorsRecursively( + PaintLayer* layer, + UpdateType& update_type, + AncestorInfo& info) { + if (!layer) + return; + + // We first recursively call ApplyAncestorInfoToSelfAndAncestorsRecursively() + // to ensure that we start to compute the geometry_map_ and AncestorInfo from + // the root layer (as we need to do a top-down tree walk to incrementally + // update this information). + ApplyAncestorInfoToSelfAndAncestorsRecursively(layer->Parent(), update_type, + info); + geometry_map_.PushMappingsToAncestor(layer, layer->Parent()); + UpdateAncestorInfo(layer, update_type, info); +} + +void CompositingInputsUpdater::UpdateSelfAndDescendantsRecursively( + PaintLayer* layer, + UpdateType update_type, + AncestorInfo info) { LayoutBoxModelObject& layout_object = layer->GetLayoutObject(); const ComputedStyle& style = layout_object.StyleRef(); @@ -74,7 +105,84 @@ layer->UpdateLayerPosition(); } - geometry_map_.PushMappingsToAncestor(layer, layer->Parent()); + // geometry_map_ has been already updated in ApplyAncestorInfo() and + // UpdateAncestorInfo has been already computed in ApplyAncestorInfo() for + // layers from root_layer_ down to compositing_inputs_root_ both included. + if (layer != root_layer_ && layer != compositing_inputs_root_) { + geometry_map_.PushMappingsToAncestor(layer, layer->Parent()); + UpdateAncestorInfo(layer, update_type, info); + } + + PaintLayerCompositor* compositor = + layer->GetLayoutObject().View()->Compositor(); + + // The sequence of updates to compositing triggers goes like this: + // 1. Apply all triggers from kComboAllDirectNonStyleDeterminedReasons for + // |layer|. This may depend on ancestor composited scrolling (i.e. step + // 2 for an ancestor PaintLayer). + // 2. Put |layer| in composited scrolling mode if needed. + // 3. Reset DescendantHasDirectCompositingReason to false for |layer|. + // 4. Recurse into child PaintLayers. + // 5. Set DescendantHasDirectCompositingReason to true if it was for any + // child. + // 6. If |layer| is the root, composite if + // DescendantHasDirectCompositingReason is true for |layer|. + + layer->SetPotentialCompositingReasonsFromNonStyle( + CompositingReasonFinder::NonStyleDeterminedDirectReasons(*layer)); + + if (layer->GetScrollableArea()) { + layer->GetScrollableArea()->UpdateNeedsCompositedScrolling( + compositor->CanBeComposited(layer) && + layer->DirectCompositingReasons()); + } + + bool should_recurse = + layer->ChildNeedsCompositingInputsUpdate() || update_type == kForceUpdate; + + layer->SetDescendantHasDirectOrScrollingCompositingReason(false); + bool descendant_has_direct_compositing_reason = false; + for (PaintLayer* child = layer->FirstChild(); child; + child = child->NextSibling()) { + if (should_recurse) + UpdateSelfAndDescendantsRecursively(child, update_type, info); + descendant_has_direct_compositing_reason |= + child->DescendantHasDirectOrScrollingCompositingReason() || + child->NeedsCompositedScrolling() || + (compositor->CanBeComposited(child) && + child->DirectCompositingReasons()); + } + layer->SetDescendantHasDirectOrScrollingCompositingReason( + descendant_has_direct_compositing_reason); + + if (layer->IsRootLayer() && layer->ScrollsOverflow() && + layer->DescendantHasDirectOrScrollingCompositingReason() && + !layer->NeedsCompositedScrolling()) + layer->GetScrollableArea()->UpdateNeedsCompositedScrolling(true); + + layer->ClearChildNeedsCompositingInputsUpdate(); + + geometry_map_.PopMappingsToAncestor(layer->Parent()); + + if (layer->SelfPaintingStatusChanged()) { + layer->ClearSelfPaintingStatusChanged(); + // If the floating object becomes non-self-painting, so some ancestor should + // paint it; if it becomes self-painting, it should paint itself and no + // ancestor should paint it. + if (layout_object.IsFloating()) { + LayoutBlockFlow::UpdateAncestorShouldPaintFloatingObject( + *layer->GetLayoutBox()); + } + } + + compositor->ClearCompositingInputsRoot(); +} + +void CompositingInputsUpdater::UpdateAncestorInfo(PaintLayer* layer, + UpdateType& update_type, + AncestorInfo& info) { + LayoutBoxModelObject& layout_object = layer->GetLayoutObject(); + const ComputedStyle& style = layout_object.StyleRef(); PaintLayer* enclosing_stacking_composited_layer = info.enclosing_stacking_composited_layer; @@ -208,69 +316,8 @@ info.needs_reparent_scroll_for_fixed = false; } - PaintLayerCompositor* compositor = - layer->GetLayoutObject().View()->Compositor(); - - // The sequence of updates to compositing triggers goes like this: - // 1. Apply all triggers from kComboAllDirectNonStyleDeterminedReasons for - // |layer|. This may depend on ancestor composited scrolling (i.e. step - // 2 for an ancestor PaintLayer). - // 2. Put |layer| in composited scrolling mode if needed. - // 3. Reset DescendantHasDirectCompositingReason to false for |layer|. - // 4. Recurse into child PaintLayers. - // 5. Set DescendantHasDirectCompositingReason to true if it was for any - // child. - // 6. If |layer| is the root, composite if - // DescendantHasDirectCompositingReason is true for |layer|. - layer->SetPotentialCompositingReasonsFromNonStyle( - CompositingReasonFinder::NonStyleDeterminedDirectReasons(*layer)); - - if (layer->GetScrollableArea()) { - layer->GetScrollableArea()->UpdateNeedsCompositedScrolling( - compositor->CanBeComposited(layer) && - layer->DirectCompositingReasons()); - } - if (layer->GetLayoutObject().IsVideo()) info.is_under_video = true; - - bool should_recurse = - layer->ChildNeedsCompositingInputsUpdate() || update_type == kForceUpdate; - - layer->SetDescendantHasDirectOrScrollingCompositingReason(false); - bool descendant_has_direct_compositing_reason = false; - for (PaintLayer* child = layer->FirstChild(); child; - child = child->NextSibling()) { - if (should_recurse) - UpdateRecursive(child, update_type, info); - descendant_has_direct_compositing_reason |= - child->DescendantHasDirectOrScrollingCompositingReason() || - child->NeedsCompositedScrolling() || - (compositor->CanBeComposited(child) && - child->DirectCompositingReasons()); - } - layer->SetDescendantHasDirectOrScrollingCompositingReason( - descendant_has_direct_compositing_reason); - - if (layer->IsRootLayer() && layer->ScrollsOverflow() && - layer->DescendantHasDirectOrScrollingCompositingReason() && - !layer->NeedsCompositedScrolling()) - layer->GetScrollableArea()->UpdateNeedsCompositedScrolling(true); - - layer->ClearChildNeedsCompositingInputsUpdate(); - - geometry_map_.PopMappingsToAncestor(layer->Parent()); - - if (layer->SelfPaintingStatusChanged()) { - layer->ClearSelfPaintingStatusChanged(); - // If the floating object becomes non-self-painting, so some ancestor should - // paint it; if it becomes self-painting, it should paint itself and no - // ancestor should paint it. - if (layout_object.IsFloating()) { - LayoutBlockFlow::UpdateAncestorShouldPaintFloatingObject( - *layer->GetLayoutBox()); - } - } } void CompositingInputsUpdater::UpdateAncestorDependentCompositingInputs(
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h index 04fbc010..86574662 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h +++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
@@ -16,7 +16,8 @@ STACK_ALLOCATED(); public: - explicit CompositingInputsUpdater(PaintLayer* root_layer); + explicit CompositingInputsUpdater(PaintLayer* root_layer, + PaintLayer* compositing_inputs_root); ~CompositingInputsUpdater(); void Update(); @@ -63,12 +64,23 @@ bool is_under_video = false; }; - void UpdateRecursive(PaintLayer*, UpdateType, AncestorInfo); + void UpdateSelfAndDescendantsRecursively(PaintLayer*, + UpdateType, + AncestorInfo); void UpdateAncestorDependentCompositingInputs(PaintLayer*, const AncestorInfo&); + // This is a recursive method to compute the geometry_map_ and AncestorInfo + // starting from the root layer down to the compositing_inputs_root_. + void ApplyAncestorInfoToSelfAndAncestorsRecursively(PaintLayer*, + UpdateType&, + AncestorInfo&); + // This method takes care of updating AncestorInfo taking into account the + // current value of AncestorInfo. + void UpdateAncestorInfo(PaintLayer*, UpdateType&, AncestorInfo&); LayoutGeometryMap geometry_map_; PaintLayer* root_layer_; + PaintLayer* compositing_inputs_root_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc index da735a7ee..b6a7ff2d 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -372,8 +372,9 @@ CompositingUpdateType update_type) { DCHECK(!HasAcceleratedCompositing()); - if (update_type >= kCompositingUpdateAfterCompositingInputChange) - CompositingInputsUpdater(RootLayer()).Update(); + if (update_type >= kCompositingUpdateAfterCompositingInputChange) { + CompositingInputsUpdater(RootLayer(), GetCompositingInputsRoot()).Update(); + } #if DCHECK_IS_ON() CompositingInputsUpdater::AssertNeedsCompositingInputsUpdateBitsCleared( @@ -459,7 +460,7 @@ Vector<PaintLayer*> layers_needing_paint_invalidation; if (update_type >= kCompositingUpdateAfterCompositingInputChange) { - CompositingInputsUpdater(update_root).Update(); + CompositingInputsUpdater(RootLayer(), GetCompositingInputsRoot()).Update(); #if DCHECK_IS_ON() // FIXME: Move this check to the end of the compositing update.
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h index 348f71a4..7264ea9 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -30,6 +30,7 @@ #include "base/gtest_prod_util.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/document_lifecycle.h" +#include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_root.h" #include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h" namespace blink { @@ -156,6 +157,16 @@ void AttachRootLayerViaChromeClient(); + PaintLayer* GetCompositingInputsRoot() { + return compositing_inputs_root_.Get(); + } + + void ClearCompositingInputsRoot() { compositing_inputs_root_.Clear(); } + + void UpdateCompositingInputsRoot(PaintLayer* layer) { + compositing_inputs_root_.Update(layer); + } + private: #if DCHECK_IS_ON() void AssertNoUnresolvedDirtyBits(); @@ -222,6 +233,8 @@ }; RootLayerAttachment root_layer_attachment_; + CompositingInputsRoot compositing_inputs_root_; + FRIEND_TEST_ALL_PREFIXES(FrameThrottlingTest, IntersectionObservationOverridesThrottling); };
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc index 993d399..2add7985 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc
@@ -110,4 +110,35 @@ EXPECT_EQ(main_graphics_layer_parent, main_graphics_layer->Parent()); } +TEST_F(PaintLayerCompositorTest, CompositingInputsUpdateStopsContainStrict) { + SetHtmlInnerHTML(R"HTML( + <style> + div { + position: relative; + } + #wrapper { + contain: strict; + } + </style> + <div id='wrapper'> + <div id='target'></div> + </div> + )HTML"); + + PaintLayer* wrapper = GetPaintLayerByElementId("wrapper"); + PaintLayer* target = GetPaintLayerByElementId("target"); + EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate()); + EXPECT_FALSE(target->NeedsCompositingInputsUpdate()); + + target->SetNeedsCompositingInputsUpdate(); + EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate()); + EXPECT_TRUE(target->NeedsCompositingInputsUpdate()); + + GetDocument().View()->UpdateLifecycleToCompositingInputsClean(); + EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean, + GetDocument().Lifecycle().GetState()); + EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate()); + EXPECT_FALSE(target->NeedsCompositingInputsUpdate()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/image_element_timing.h b/third_party/blink/renderer/core/paint/image_element_timing.h index 1c3b110..f009389 100644 --- a/third_party/blink/renderer/core/paint/image_element_timing.h +++ b/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -45,7 +45,7 @@ void Trace(blink::Visitor*) override; private: - FRIEND_TEST_ALL_PREFIXES(ImageElementTimingTest, ImageInsideSVG); + friend class ImageElementTimingTest; // Callback for the swap promise. Reports paint timestamps. void ReportImagePaintSwapTime(WebLayerTreeView::SwapResult, base::TimeTicks timestamp);
diff --git a/third_party/blink/renderer/core/paint/image_element_timing_test.cc b/third_party/blink/renderer/core/paint/image_element_timing_test.cc index 4e59631..528befe 100644 --- a/third_party/blink/renderer/core/paint/image_element_timing_test.cc +++ b/third_party/blink/renderer/core/paint/image_element_timing_test.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/paint/image_element_timing.h" #include "third_party/blink/renderer/core/layout/layout_image.h" +#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h" #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" @@ -24,8 +25,17 @@ return layout_image; } - const ImageElementTiming& GetImageElementTiming() { - return ImageElementTiming::From(*GetDocument().domWindow()); + // Similar to above but for a LayoutSVGImage. + LayoutSVGImage* SetSVGImageResource(const char* id, int width, int height) { + ImageResourceContent* content = CreateImageForTest(width, height); + auto* layout_image = ToLayoutSVGImage(GetLayoutObjectByElementId(id)); + layout_image->ImageResource()->SetImageResource(content); + return layout_image; + } + + const WTF::HashSet<const LayoutObject*>& GetImagesNotified() { + return ImageElementTiming::From(*GetDocument().domWindow()) + .images_notified_; } private: @@ -59,9 +69,44 @@ // Enable compositing and also update document lifecycle. EnableCompositing(); - const ImageElementTiming& timing = GetImageElementTiming(); // |layout_image| should have had its paint notified to ImageElementTiming. - EXPECT_TRUE(timing.images_notified_.Contains(layout_image)); + EXPECT_TRUE(GetImagesNotified().Contains(layout_image)); +} + +TEST_F(ImageElementTimingTest, ImageRemoved) { + EnableCompositing(); + GetDocument().SetBaseURLOverride(KURL("http://test.com")); + SetBodyInnerHTML(R"HTML( + <img id="target" style='width: 100px; height: 100px;'/> + )HTML"); + LayoutImage* layout_image = SetImageResource("target", 5, 5); + ASSERT_TRUE(layout_image); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetImagesNotified().Contains(layout_image)); + + GetDocument().getElementById("target")->remove(); + // |layout_image| should no longer be part of |images_notified| since it will + // be destroyed. + EXPECT_TRUE(GetImagesNotified().IsEmpty()); +} + +TEST_F(ImageElementTimingTest, SVGImageRemoved) { + EnableCompositing(); + GetDocument().SetBaseURLOverride(KURL("http://test.com")); + SetBodyInnerHTML(R"HTML( + <svg> + <image id="target" style='width: 100px; height: 100px;'/> + </svg> + )HTML"); + LayoutSVGImage* layout_image = SetSVGImageResource("target", 5, 5); + ASSERT_TRUE(layout_image); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetImagesNotified().Contains(layout_image)); + + GetDocument().getElementById("target")->remove(); + // |layout_image| should no longer be part of |images_notified| since it will + // be destroyed. + EXPECT_TRUE(GetImagesNotified().IsEmpty()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 9adae7e..38c33fd8 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -449,8 +449,8 @@ DrawingRecorder recorder(paint_info.context, box_fragment_, paint_info.phase); LayoutRect paint_rect = LayoutRect(paint_offset, box_fragment_.Size().ToLayoutSize()); - PaintMaskImages(paint_info, paint_rect, box_fragment_, geometry, - border_edges_.line_left, border_edges_.line_right); + PaintMaskImages(paint_info, paint_rect, *box_fragment_.GetLayoutObject(), + geometry, border_edges_.line_left, border_edges_.line_right); } // TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to @@ -631,9 +631,10 @@ ShouldPaintBoxFragmentBorders(layout_object)) { Node* generating_node = layout_object.GeneratingNode(); const Document& document = layout_object.GetDocument(); - PaintBorder(box_fragment_, document, generating_node, paint_info, - paint_rect, style, box_decoration_data.bleed_avoidance, - border_edges_.line_left, border_edges_.line_right); + PaintBorder(*box_fragment_.GetLayoutObject(), document, generating_node, + paint_info, paint_rect, style, + box_decoration_data.bleed_avoidance, border_edges_.line_left, + border_edges_.line_right); } }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc index 603f9a683..34d98e9 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
@@ -93,8 +93,9 @@ LayoutObject* layout_object = fieldset_.GetLayoutObject(); Node* node = layout_object->GeneratingNode(); - fragment_painter.PaintBorder(fieldset_, layout_object->GetDocument(), node, - paint_info, contracted_rect, fieldset_.Style()); + fragment_painter.PaintBorder(*fieldset_.GetLayoutObject(), + layout_object->GetDocument(), node, paint_info, + contracted_rect, fieldset_.Style()); } void NGFieldsetPainter::PaintLegend(const NGPaintFragment& legend,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc index 1db5137..d489a0f 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -20,19 +20,28 @@ namespace blink { NGInlineBoxFragmentPainter::NGInlineBoxFragmentPainter( - const NGPaintFragment& inline_box_fragment) - : InlineBoxPainterBase( - inline_box_fragment, - &inline_box_fragment.GetLayoutObject()->GetDocument(), - inline_box_fragment.GetLayoutObject()->GeneratingNode(), - inline_box_fragment.Style(), - // TODO(layout-dev): Should be first-line style. - inline_box_fragment.Style()), + const NGPaintFragment& inline_box_fragment, + const LayoutObject& layout_object, + const ComputedStyle& style, + const ComputedStyle& line_style) + : InlineBoxPainterBase(layout_object, + &layout_object.GetDocument(), + layout_object.GeneratingNode(), + style, + line_style), inline_box_fragment_(inline_box_fragment), border_edges_(NGBorderEdges::FromPhysical( inline_box_fragment.PhysicalFragment().BorderEdges(), - inline_box_fragment.Style().GetWritingMode())) { -} + style.GetWritingMode())) {} + +NGInlineBoxFragmentPainter::NGInlineBoxFragmentPainter( + const NGPaintFragment& inline_box_fragment) + : NGInlineBoxFragmentPainter( + inline_box_fragment, + *inline_box_fragment.GetLayoutObject(), + inline_box_fragment.Style(), + // TODO(layout-dev): Should be first-line style. + inline_box_fragment.Style()) {} void NGInlineBoxFragmentPainter::Paint(const PaintInfo& paint_info, const LayoutPoint& paint_offset) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h index 1b4a60e..f08bd538 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h +++ b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
@@ -45,6 +45,11 @@ const LayoutRect& paint_rect) override; private: + NGInlineBoxFragmentPainter(const NGPaintFragment& inline_box_fragment, + const LayoutObject& layout_object, + const ComputedStyle& style, + const ComputedStyle& line_style); + void PaintBackgroundBorderShadow(const PaintInfo&, const LayoutPoint& paint_offset);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc index 9504842..38ff7981 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -36,8 +36,7 @@ namespace { struct SameSizeAsNGPaintFragment : public RefCounted<NGPaintFragment>, - public DisplayItemClient, - public ImageResourceObserver { + public DisplayItemClient { void* pointers[6]; NGPhysicalOffset offsets[2]; unsigned flags; @@ -316,25 +315,6 @@ return paint_fragment; } -const NGPaintFragment* NGPaintFragment::Last() const { - for (const NGPaintFragment* fragment = this;;) { - const NGPaintFragment* next = fragment->Next(); - if (!next) - return fragment; - fragment = next; - } -} - -const NGPaintFragment* NGPaintFragment::Last( - const NGBreakToken& break_token) const { - for (const NGPaintFragment* fragment = this; fragment; - fragment = fragment->Next()) { - if (fragment->PhysicalFragment().BreakToken() == &break_token) - return fragment; - } - return nullptr; -} - scoped_refptr<NGPaintFragment>* NGPaintFragment::Find( scoped_refptr<NGPaintFragment>* fragment, const NGBlockBreakToken* break_token) { @@ -358,10 +338,6 @@ NOTREACHED(); } -void NGPaintFragment::SetNext(scoped_refptr<NGPaintFragment> fragment) { - next_fragmented_ = std::move(fragment); -} - bool NGPaintFragment::IsDescendantOfNotSelf( const NGPaintFragment& ancestor) const { for (const NGPaintFragment* fragment = Parent(); fragment;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h index 4bf2e757..8a2e2a6 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -9,7 +9,6 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" -#include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" @@ -36,8 +35,7 @@ // - image (<img>, svg <image>) or video (<video>) elements that are // placeholders for displaying them. class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>, - public DisplayItemClient, - public ImageResourceObserver { + public DisplayItemClient { public: NGPaintFragment(scoped_refptr<const NGPhysicalFragment>, NGPhysicalOffset offset, @@ -53,11 +51,6 @@ return *physical_fragment_; } - // Next/last fragment for when this is fragmented. - const NGPaintFragment* Next() const { return next_fragmented_.get(); } - void SetNext(scoped_refptr<NGPaintFragment>); - const NGPaintFragment* Last() const; - const NGPaintFragment* Last(const NGBreakToken&) const; static scoped_refptr<NGPaintFragment>* Find(scoped_refptr<NGPaintFragment>*, const NGBlockBreakToken*);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 3e43e99d..8c15805 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1085,20 +1085,39 @@ MarkAncestorChainForFlagsUpdate(); } +void PaintLayer::SetChildNeedsCompositingInputsUpdateUpToAncestor( + PaintLayer* ancestor) { + DCHECK(ancestor); + + for (auto* layer = this; layer && layer != ancestor; layer = layer->Parent()) + layer->child_needs_compositing_inputs_update_ = true; + + ancestor->child_needs_compositing_inputs_update_ = true; +} + void PaintLayer::SetNeedsCompositingInputsUpdateInternal() { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) return; needs_ancestor_dependent_compositing_inputs_update_ = true; + PaintLayer* last_ancestor = nullptr; for (PaintLayer* current = this; current && !current->child_needs_compositing_inputs_update_; - current = current->Parent()) + current = current->Parent()) { + last_ancestor = current; current->child_needs_compositing_inputs_update_ = true; + if (Compositor() && + current->GetLayoutObject().ShouldApplyStrictContainment()) + break; + } if (Compositor()) { Compositor()->SetNeedsCompositingUpdate( kCompositingUpdateAfterCompositingInputChange); + + if (last_ancestor) + Compositor()->UpdateCompositingInputsRoot(last_ancestor); } } @@ -3413,6 +3432,43 @@ needs_repaint_ = false; } +const PaintLayer* PaintLayer::CommonAncestor(const PaintLayer* other) const { + DCHECK(other); + if (this == other) + return this; + + int this_depth = 0; + for (auto* layer = this; layer; layer = layer->Parent()) { + if (layer == other) + return layer; + this_depth++; + } + int other_depth = 0; + for (auto* layer = other; layer; layer = layer->Parent()) { + if (layer == this) + return layer; + other_depth++; + } + + const PaintLayer* this_iterator = this; + const PaintLayer* other_iterator = other; + for (; this_depth > other_depth; this_depth--) + this_iterator = this_iterator->Parent(); + for (; other_depth > this_depth; other_depth--) + other_iterator = other_iterator->Parent(); + + while (this_iterator) { + if (this_iterator == other_iterator) + return this_iterator; + this_iterator = this_iterator->Parent(); + other_iterator = other_iterator->Parent(); + } + + DCHECK(!this_iterator); + DCHECK(!other_iterator); + return nullptr; +} + DisableCompositingQueryAsserts::DisableCompositingQueryAsserts() : disabler_(&g_compositing_query_mode, kCompositingQueriesAreAllowed) {}
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index 7934510b..7d619ac 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -245,6 +245,8 @@ PaintLayer* FirstChild() const { return first_; } PaintLayer* LastChild() const { return last_; } + const PaintLayer* CommonAncestor(const PaintLayer*) const; + // TODO(wangxianzhu): Find a better name for it. 'paintContainer' might be // good but we can't use it for now because it conflicts with // PaintInfo::paintContainer. @@ -764,6 +766,9 @@ void SetNeedsVisualOverflowRecalc(); void SetNeedsCompositingInputsUpdate(); + // This methods marks everything from this layer up to the |ancestor| argument + // (both included). + void SetChildNeedsCompositingInputsUpdateUpToAncestor(PaintLayer* ancestor); // Use this internal method only for cases during the descendant-dependent // tree walk. bool ChildNeedsCompositingInputsUpdate() const { @@ -1064,7 +1069,7 @@ // for the definition of a replaced normal-flow stacking element. bool IsReplacedNormalFlowStacking() const; - void SetNeeedsCompositingReasonsUpdate() { + void SetNeedsCompositingReasonsUpdate() { needs_compositing_reasons_update_ = true; }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.h b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.h index c813fab4..76ad5db 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.h +++ b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.h
@@ -169,12 +169,6 @@ // have z-order lists. bool z_order_lists_dirty_ : 1; - // This attribute caches whether the element was stacked. It's needed to check - // the current stacked status (instead of the new stacked status determined by - // the new style which has not been realized yet) when a layer is removed due - // to style change. - bool is_stacked_ : 1; - #if DCHECK_IS_ON() bool layer_list_mutation_allowed_ : 1; #endif
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc index 82107f7..b35bf3b 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_test.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -1896,4 +1896,67 @@ EXPECT_TRUE(target->Parent()->GetLayoutObject().NeedsPaintPropertyUpdate()); } +TEST_P(PaintLayerTest, PaintLayerCommonAncestor) { + SetBodyInnerHTML(R"HTML( + <style> + div { + position: relative; + } + </style> + <div id='wrapper'> + <div id='target1'> + <div id='target1x1'></div> + </div> + <div id='target2'></div> + <div> + <div id='target3'></div> + </div> + </div> + )HTML"); + + PaintLayer* wrapper = GetPaintLayerByElementId("wrapper"); + PaintLayer* target1 = GetPaintLayerByElementId("target1"); + PaintLayer* target1x1 = GetPaintLayerByElementId("target1x1"); + PaintLayer* target2 = GetPaintLayerByElementId("target2"); + PaintLayer* target3 = GetPaintLayerByElementId("target3"); + + EXPECT_EQ(target1->CommonAncestor(target1), target1); + EXPECT_EQ(target1->CommonAncestor(target1x1), target1); + EXPECT_EQ(target1->CommonAncestor(target2), wrapper); + EXPECT_EQ(target1->CommonAncestor(target3), wrapper); + + EXPECT_EQ(target1x1->CommonAncestor(target1), target1); + EXPECT_EQ(target1x1->CommonAncestor(target1x1), target1x1); + EXPECT_EQ(target1x1->CommonAncestor(target2), wrapper); + EXPECT_EQ(target1x1->CommonAncestor(target3), wrapper); + + EXPECT_EQ(target2->CommonAncestor(target1), wrapper); + EXPECT_EQ(target2->CommonAncestor(target1x1), wrapper); + EXPECT_EQ(target2->CommonAncestor(target2), target2); + EXPECT_EQ(target2->CommonAncestor(target3), wrapper); + + EXPECT_EQ(target3->CommonAncestor(target1), wrapper); + EXPECT_EQ(target3->CommonAncestor(target1x1), wrapper); + EXPECT_EQ(target3->CommonAncestor(target2), wrapper); + EXPECT_EQ(target3->CommonAncestor(target3), target3); +} + +TEST_P(PaintLayerTest, PaintLayerCommonAncestorBody) { + SetBodyInnerHTML(R"HTML( + <style> + body, div { + position: relative; + } + </style> + <div id='target1'></div> + <div id='target2'></div> + )HTML"); + + PaintLayer* target1 = GetPaintLayerByElementId("target1"); + PaintLayer* target2 = GetPaintLayerByElementId("target2"); + + EXPECT_EQ(target1->CommonAncestor(target2)->GetLayoutObject(), + GetDocument().body()->GetLayoutObject()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/script/modulator.cc b/third_party/blink/renderer/core/script/modulator.cc index b0561f36..cfa10329 100644 --- a/third_party/blink/renderer/core/script/modulator.cc +++ b/third_party/blink/renderer/core/script/modulator.cc
@@ -42,20 +42,22 @@ // See comment in LocalDOMWindow::modulator_ for this workaround. LocalDOMWindow* window = document->ExecutingWindow(); window->SetModulator(modulator); - } else if (auto* scope = DynamicTo<WorkletGlobalScope>(execution_context)) { + } else if (auto* worklet_scope = + DynamicTo<WorkletGlobalScope>(execution_context)) { modulator = WorkletModulatorImpl::Create(script_state); Modulator::SetModulator(script_state, modulator); // See comment in WorkerOrWorkletGlobalScope::modulator_ for this // workaround. - scope->SetModulator(modulator); - } else if (auto* scope = DynamicTo<WorkerGlobalScope>(execution_context)) { + worklet_scope->SetModulator(modulator); + } else if (auto* worker_scope = + DynamicTo<WorkerGlobalScope>(execution_context)) { modulator = WorkerModulatorImpl::Create(script_state); Modulator::SetModulator(script_state, modulator); // See comment in WorkerOrWorkletGlobalScope::modulator_ for this // workaround. - scope->SetModulator(modulator); + worker_scope->SetModulator(modulator); } else { NOTREACHED(); }
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 152e7ec1..9eacec8 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -883,6 +883,15 @@ HasCurrentFilterAnimation() != other.HasCurrentFilterAnimation() || HasCurrentBackdropFilterAnimation() != other.HasCurrentBackdropFilterAnimation() || + IsRunningTransformAnimationOnCompositor() != + other.IsRunningTransformAnimationOnCompositor() || + IsRunningOpacityAnimationOnCompositor() != + other.IsRunningOpacityAnimationOnCompositor() || + IsRunningFilterAnimationOnCompositor() != + other.IsRunningFilterAnimationOnCompositor() || + IsRunningBackdropFilterAnimationOnCompositor() != + other.IsRunningBackdropFilterAnimationOnCompositor() || + SubtreeWillChangeContents() != other.SubtreeWillChangeContents() || BackfaceVisibility() != other.BackfaceVisibility() || HasWillChangeCompositingHint() != other.HasWillChangeCompositingHint() || UsedTransformStyle3D() != other.UsedTransformStyle3D() ||
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index fa33f59..5af2e920 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -282,8 +282,9 @@ // flat tree in the presence of display:contents. kDisplayAffectingDescendantStyles, }; - static Difference ComputeDifference(const ComputedStyle* old_style, - const ComputedStyle* new_style); + CORE_EXPORT static Difference ComputeDifference( + const ComputedStyle* old_style, + const ComputedStyle* new_style); // Returns true if the ComputedStyle change requires a LayoutObject re-attach. static bool NeedsReattachLayoutTree(const ComputedStyle* old_style, @@ -317,8 +318,8 @@ StyleContentAlignmentData ResolvedJustifyContent( const StyleContentAlignmentData& normal_behaviour) const; - StyleDifference VisualInvalidationDiff(const Document&, - const ComputedStyle&) const; + CORE_EXPORT StyleDifference + VisualInvalidationDiff(const Document&, const ComputedStyle&) const; CORE_EXPORT void InheritFrom(const ComputedStyle& inherit_parent, IsAtShadowBoundary = kNotAtShadowBoundary);
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 index 4279172..9846eb76 100644 --- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 +++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -783,7 +783,6 @@ field_template: "primitive", type_name: "bool", field_group: "*", - custom_compare: true, default_value: "false", }, { @@ -791,7 +790,6 @@ field_template: "primitive", type_name: "bool", field_group: "*", - custom_compare: true, default_value: "false", }, { @@ -799,7 +797,6 @@ field_template: "primitive", type_name: "bool", field_group: "*", - custom_compare: true, default_value: "false", }, { @@ -807,7 +804,6 @@ field_template: "primitive", type_name: "bool", field_group: "*", - custom_compare: true, default_value: "false", }, // A stacking context is painted atomically and defines a stacking order,
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc index a2e26f8..b05fbee5 100644 --- a/third_party/blink/renderer/core/style/computed_style_test.cc +++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -7,6 +7,7 @@ #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/css/css_gradient_value.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/style/clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_value.h" @@ -401,4 +402,33 @@ EXPECT_TRUE(style->BorderSizeEquals(*other)); } +#define TEST_ANIMATION_FLAG(flag, inherited) \ + do { \ + auto style = ComputedStyle::Create(); \ + auto other = ComputedStyle::Create(); \ + EXPECT_FALSE(style->flag()); \ + EXPECT_FALSE(other->flag()); \ + style->Set##flag(true); \ + EXPECT_TRUE(style->flag()); \ + EXPECT_EQ(ComputedStyle::Difference::inherited, \ + ComputedStyle::ComputeDifference(style.get(), other.get())); \ + auto diff = style->VisualInvalidationDiff(*document, *other); \ + EXPECT_TRUE(diff.HasDifference()); \ + EXPECT_TRUE(diff.CompositingReasonsChanged()); \ + } while (false) + +TEST(ComputedStyleTest, AnimationFlags) { + Persistent<Document> document = Document::CreateForTest(); + TEST_ANIMATION_FLAG(HasCurrentTransformAnimation, kNonInherited); + TEST_ANIMATION_FLAG(HasCurrentOpacityAnimation, kNonInherited); + TEST_ANIMATION_FLAG(HasCurrentFilterAnimation, kNonInherited); + TEST_ANIMATION_FLAG(HasCurrentBackdropFilterAnimation, kNonInherited); + TEST_ANIMATION_FLAG(IsRunningTransformAnimationOnCompositor, kNonInherited); + TEST_ANIMATION_FLAG(IsRunningOpacityAnimationOnCompositor, kNonInherited); + TEST_ANIMATION_FLAG(IsRunningFilterAnimationOnCompositor, kNonInherited); + TEST_ANIMATION_FLAG(IsRunningBackdropFilterAnimationOnCompositor, + kNonInherited); + TEST_ANIMATION_FLAG(SubtreeWillChangeContents, kInherited); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_difference.h b/third_party/blink/renderer/core/style/style_difference.h index e5a387a6..4e80373 100644 --- a/third_party/blink/renderer/core/style/style_difference.h +++ b/third_party/blink/renderer/core/style/style_difference.h
@@ -40,13 +40,13 @@ visual_rect_update_(false), property_specific_differences_(0), scroll_anchor_disabling_property_changed_(false), - composited_reasons_changed_(false) {} + compositing_reasons_changed_(false) {} bool HasDifference() const { return paint_invalidation_type_ || layout_type_ || property_specific_differences_ || recompute_overflow_ || visual_rect_update_ || scroll_anchor_disabling_property_changed_ || - composited_reasons_changed_; + compositing_reasons_changed_; } bool HasAtMostPropertySpecificDifferences( @@ -167,8 +167,10 @@ void SetScrollAnchorDisablingPropertyChanged() { scroll_anchor_disabling_property_changed_ = true; } - bool CompositingReasonsChanged() const { return composited_reasons_changed_; } - void SetCompositingReasonsChanged() { composited_reasons_changed_ = true; } + bool CompositingReasonsChanged() const { + return compositing_reasons_changed_; + } + void SetCompositingReasonsChanged() { compositing_reasons_changed_ = true; } private: static constexpr int kPropertyDifferenceCount = 10; @@ -189,7 +191,7 @@ unsigned visual_rect_update_ : 1; unsigned property_specific_differences_ : kPropertyDifferenceCount; unsigned scroll_anchor_disabling_property_changed_ : 1; - unsigned composited_reasons_changed_ : 1; + unsigned compositing_reasons_changed_ : 1; }; CORE_EXPORT std::ostream& operator<<(std::ostream&, const StyleDifference&);
diff --git a/third_party/blink/renderer/core/timing/memory_info_test.cc b/third_party/blink/renderer/core/timing/memory_info_test.cc index 5cebb2f..ec95e15 100644 --- a/third_party/blink/renderer/core/timing/memory_info_test.cc +++ b/third_party/blink/renderer/core/timing/memory_info_test.cc
@@ -54,6 +54,12 @@ EXPECT_EQ(10000000u, QuantizeMemorySize(3)); EXPECT_EQ(10000000u, QuantizeMemorySize(1)); EXPECT_EQ(10000000u, QuantizeMemorySize(0)); + // Rounding differences between OS's may affect the precise value of the last + // bucket. + EXPECT_LE(3760000000u, + QuantizeMemorySize(std::numeric_limits<size_t>::max())); + EXPECT_GT(4000000000u, + QuantizeMemorySize(std::numeric_limits<size_t>::max())); } static constexpr int kModForBucketizationCheck = 100000;
diff --git a/third_party/blink/renderer/devtools/BUILD.gn b/third_party/blink/renderer/devtools/BUILD.gn index 1b7f2fe..98860d8 100644 --- a/third_party/blink/renderer/devtools/BUILD.gn +++ b/third_party/blink/renderer/devtools/BUILD.gn
@@ -466,6 +466,7 @@ "front_end/perf_ui/FlameChart.js", "front_end/perf_ui/GCActionDelegate.js", "front_end/perf_ui/LineLevelProfile.js", + "front_end/perf_ui/LiveHeapProfile.js", "front_end/perf_ui/NetworkPriorities.js", "front_end/perf_ui/OverviewGrid.js", "front_end/perf_ui/PieChart.js",
diff --git a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js index 4ef306a2..bc7d485 100644 --- a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
@@ -1394,6 +1394,8 @@ const isShorthand = !!style.longhandProperties(property.name).length; const inherited = this.isPropertyInherited(property.name); const overloaded = this._isPropertyOverloaded(property); + if (style.parentRule && style.parentRule.isUserAgent() && inherited) + continue; const item = new Elements.StylePropertyTreeElement( this._parentPane, this._matchedStyles, property, isShorthand, inherited, overloaded, false); this.propertiesTreeOutline.appendChild(item);
diff --git a/third_party/blink/renderer/devtools/front_end/help/Help.js b/third_party/blink/renderer/devtools/front_end/help/Help.js index 38e2ca0..b4846e71 100644 --- a/third_party/blink/renderer/devtools/front_end/help/Help.js +++ b/third_party/blink/renderer/devtools/front_end/help/Help.js
@@ -60,7 +60,8 @@ * @override */ run() { - Help._showReleaseNoteIfNeeded(); + if (!Host.isUnderTest()) + Help._showReleaseNoteIfNeeded(); } };
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js index 3d3214e..53e24c0a 100644 --- a/third_party/blink/renderer/devtools/front_end/main/Main.js +++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -106,15 +106,16 @@ _initializeExperiments() { // Keep this sorted alphabetically: both keys and values. Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes'); + Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel'); Runtime.experiments.register('backgroundServices', 'Background web platform feature events', true); Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true); Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping'); Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true); + Runtime.experiments.register('liveHeapProfile', 'Live heap profile', true); Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true); Runtime.experiments.register('protocolMonitor', 'Protocol Monitor'); Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true); Runtime.experiments.register('sourceDiff', 'Source diff'); - Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel'); Runtime.experiments.register('splitInDrawer', 'Split in drawer', true); Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true); @@ -128,6 +129,9 @@ Runtime.experiments.cleanUpStaleExperiments(); Runtime.experiments.setDefaultExperiments([]); + + if (Host.isUnderTest() && Runtime.queryParam('test').includes('live-line-level-heap-profile.js')) + Runtime.experiments.enableForTest('liveHeapProfile'); } /** @@ -261,10 +265,8 @@ Main.Main.time('Main._lateInitialization'); this._registerShortcuts(); Extensions.extensionServer.initializeExtensions(); - if (!Host.isUnderTest()) { - for (const extension of self.runtime.extensions('late-initialization')) - extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()); - } + for (const extension of self.runtime.extensions('late-initialization')) + extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()); Main.Main.timeEnd('Main._lateInitialization'); }
diff --git a/third_party/blink/renderer/devtools/front_end/perf_ui/LineLevelProfile.js b/third_party/blink/renderer/devtools/front_end/perf_ui/LineLevelProfile.js index 4541b619..c4ef519 100644 --- a/third_party/blink/renderer/devtools/front_end/perf_ui/LineLevelProfile.js +++ b/third_party/blink/renderer/devtools/front_end/perf_ui/LineLevelProfile.js
@@ -254,7 +254,7 @@ _createElement(type, value) { const element = createElementWithClass('div', 'text-editor-line-marker-text'); if (type === 'performance') { - const intensity = Number.constrain(Math.log10(1 + 2 * value) / 5, 0.02, 1); + const intensity = Number.constrain(Math.log10(1 + 10 * value) / 5, 0.02, 1); element.textContent = Common.UIString('%.1f', value); element.style.backgroundColor = `hsla(44, 100%, 50%, ${intensity.toFixed(3)})`; element.createChild('span', 'line-marker-units').textContent = ls`ms`;
diff --git a/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js b/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js new file mode 100644 index 0000000..fc275a8 --- /dev/null +++ b/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js
@@ -0,0 +1,59 @@ +// Copyright 2019 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. + +/** + * @implements {Common.Runnable} + * @implements {SDK.SDKModelObserver<!SDK.HeapProfilerModel>} + */ +PerfUI.LiveHeapProfile = class { + /** + * @override + */ + run() { + SDK.targetManager.observeModels(SDK.HeapProfilerModel, this); + requestIdleCallback(() => this.onUpdateProfiles()); + PerfUI.LiveHeapProfile.hasStartedForTest(true); + } + + /** + * @param {boolean=} started + * @return {!Promise} + */ + static hasStartedForTest(started) { + if (!PerfUI.LiveHeapProfile._startedPromise) + PerfUI.LiveHeapProfile._startedPromise = new Promise(r => PerfUI.LiveHeapProfile._startedCallback = r); + if (started) + PerfUI.LiveHeapProfile._startedCallback(); + return PerfUI.LiveHeapProfile._startedPromise; + } + + /** + * @override + * @param {!SDK.HeapProfilerModel} model + */ + modelAdded(model) { + model.startSampling(1024); + } + + /** + * @override + * @param {!SDK.HeapProfilerModel} model + */ + modelRemoved(model) { + model.stopSampling(); + } + + async onUpdateProfiles() { + const models = SDK.targetManager.models(SDK.HeapProfilerModel); + const profiles = await Promise.all(models.map(model => model.getSamplingProfile())); + const lineLevelProfile = PerfUI.LineLevelProfile.Memory.instance(); + lineLevelProfile.reset(); + for (let i = 0; i < profiles.length; ++i) { + if (profiles[i]) + lineLevelProfile.appendHeapProfile(profiles[i], models[i].target()); + } + const updateInterval = Host.isUnderTest() ? 10 : 5000; + setTimeout(() => requestIdleCallback(() => this.onUpdateProfiles()), updateInterval); + } +};
diff --git a/third_party/blink/renderer/devtools/front_end/perf_ui/module.json b/third_party/blink/renderer/devtools/front_end/perf_ui/module.json index ce8d46c9..476922e1 100644 --- a/third_party/blink/renderer/devtools/front_end/perf_ui/module.json +++ b/third_party/blink/renderer/devtools/front_end/perf_ui/module.json
@@ -1,6 +1,11 @@ { "extensions": [ { + "type": "late-initialization", + "className": "PerfUI.LiveHeapProfile", + "experiment": "liveHeapProfile" + }, + { "type": "@SourceFrame.LineDecorator", "className": "PerfUI.LineLevelProfile.LineDecorator", "decoratorType": "performance" @@ -51,6 +56,7 @@ "FlameChart.js", "GCActionDelegate.js", "LineLevelProfile.js", + "LiveHeapProfile.js", "NetworkPriorities.js", "OverviewGrid.js", "PieChart.js",
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/CSSMatchedStyles.js b/third_party/blink/renderer/devtools/front_end/sdk/CSSMatchedStyles.js index 7feefae..89af71b9 100644 --- a/third_party/blink/renderer/devtools/front_end/sdk/CSSMatchedStyles.js +++ b/third_party/blink/renderer/devtools/front_end/sdk/CSSMatchedStyles.js
@@ -38,6 +38,14 @@ this._nodeForStyle = new Map(); /** @type {!Set<!SDK.CSSStyleDeclaration>} */ this._inheritedStyles = new Set(); + + for (const result of matchedPayload) + cleanUserAgentSelectors(result); + for (const inheritedResult of inheritedPayload) { + for (const result of inheritedResult.matchedCSSRules) + cleanUserAgentSelectors(result); + } + this._mainDOMCascade = this._buildMainCascade(inlinePayload, attributesPayload, matchedPayload, inheritedPayload); this._pseudoDOMCascades = this._buildPseudoCascades(pseudoPayload); @@ -47,6 +55,18 @@ for (const style of domCascade.styles()) this._styleToDOMCascade.set(style, domCascade); } + + /** + * @param {!Protocol.CSS.RuleMatch} ruleMatch + */ + function cleanUserAgentSelectors(ruleMatch) { + const {matchingSelectors, rule} = ruleMatch; + if (rule.origin !== 'user-agent' || !matchingSelectors.length) + return; + rule.selectorList.selectors = rule.selectorList.selectors.filter((item, i) => matchingSelectors.includes(i)); + rule.selectorList.text = rule.selectorList.selectors.map(item => item.text).join(', '); + ruleMatch.matchingSelectors = matchingSelectors.map((item, i) => i); + } } /**
diff --git a/third_party/blink/renderer/devtools/front_end/test_runner/TestRunner.js b/third_party/blink/renderer/devtools/front_end/test_runner/TestRunner.js index 8848d38a..32cb07e 100644 --- a/third_party/blink/renderer/devtools/front_end/test_runner/TestRunner.js +++ b/third_party/blink/renderer/devtools/front_end/test_runner/TestRunner.js
@@ -1210,6 +1210,7 @@ */ TestRunner.loadedModules = function() { return self.runtime._modules.filter(module => module._loadedForTest) + .filter(module => module.name() !== 'help') .filter(module => module.name().indexOf('test_runner') === -1); };
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css index b68d407..22df9a2c9 100644 --- a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css +++ b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
@@ -9,12 +9,7 @@ overflow: visible !important; } -.CodeMirror-gutter-performance { - width: 60px; - background-color: white; - margin-left: 3px; -} - +.CodeMirror-gutter-performance, .CodeMirror-gutter-memory { width: 60px; background-color: white; @@ -437,7 +432,8 @@ } .CodeMirror .text-editor-line-marker-text span.line-marker-units { - color: #999; + color: #555; + font-size: 75%; margin-left: 3px; }
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl index 65c470a..e4c633e 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl
@@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] interface BackgroundFetchEvent : ExtendableEvent { readonly attribute BackgroundFetchRegistration registration; };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl index cd401cc..d62ceda 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl
@@ -6,7 +6,7 @@ [ Exposed=(Window,Worker), - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] interface BackgroundFetchManager { [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchManagerFetch] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options); [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGet] Promise<BackgroundFetchRegistration?> get(DOMString id);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl index f902243..ae757f28 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl
@@ -6,7 +6,7 @@ [ Exposed=(Window,Worker), - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] interface BackgroundFetchRecord { readonly attribute Request request; [CallWith=ScriptState] readonly attribute Promise<Response> responseReady;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl index 6442de9..fa906d7 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
@@ -5,7 +5,7 @@ // https://wicg.github.io/background-fetch/#background-fetch-registration [ Exposed=(Window,Worker), - OriginTrialEnabled=BackgroundFetch, + RuntimeEnabled=BackgroundFetch, ActiveScriptWrappable ] interface BackgroundFetchRegistration : EventTarget { readonly attribute DOMString id;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl index 20a3655..b494c006 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl
@@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] interface BackgroundFetchUpdateUIEvent : BackgroundFetchEvent { [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUIOptions options); }; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl b/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl index 7dc81fe2..2f9f6c0 100644 --- a/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl
@@ -6,7 +6,7 @@ [ ImplementedAs=ServiceWorkerGlobalScopeBackgroundFetch, - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] partial interface ServiceWorkerGlobalScope { attribute EventHandler onbackgroundfetchsuccess; attribute EventHandler onbackgroundfetchfail;
diff --git a/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl b/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl index 529646b..a1d9dee7 100644 --- a/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl
@@ -7,7 +7,7 @@ [ Exposed=(Window,Worker), ImplementedAs=ServiceWorkerRegistrationBackgroundFetch, - OriginTrialEnabled=BackgroundFetch + RuntimeEnabled=BackgroundFetch ] partial interface ServiceWorkerRegistration { readonly attribute BackgroundFetchManager backgroundFetch; };
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard.cc b/third_party/blink/renderer/modules/clipboard/clipboard.cc index fa4c735..57a75b78 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/clipboard/clipboard.h" +#include <utility> #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h" @@ -20,8 +21,9 @@ return ClipboardPromise::CreateForReadText(script_state); } -ScriptPromise Clipboard::write(ScriptState* script_state, Blob* data) { - return ClipboardPromise::CreateForWrite(script_state, data); +ScriptPromise Clipboard::write(ScriptState* script_state, + HeapVector<Member<Blob>> data) { + return ClipboardPromise::CreateForWrite(script_state, std::move(data)); } ScriptPromise Clipboard::writeText(ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard.h b/third_party/blink/renderer/modules/clipboard/clipboard.h index b0c38601..424b9a8 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard.h +++ b/third_party/blink/renderer/modules/clipboard/clipboard.h
@@ -26,7 +26,7 @@ ScriptPromise read(ScriptState*); ScriptPromise readText(ScriptState*); - ScriptPromise write(ScriptState*, Blob*); + ScriptPromise write(ScriptState*, HeapVector<Member<Blob>>); ScriptPromise writeText(ScriptState*, const String&); // EventTarget
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard.idl b/third_party/blink/renderer/modules/clipboard/clipboard.idl index dfe2c09..bf45d33 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard.idl +++ b/third_party/blink/renderer/modules/clipboard/clipboard.idl
@@ -11,7 +11,7 @@ [MeasureAs=AsyncClipboardAPIRead, CallWith=ScriptState, RuntimeEnabled=AsyncClipboard - ] Promise<Blob> read(); + ] Promise<sequence<Blob>> read(); [MeasureAs=AsyncClipboardAPIReadText, CallWith=ScriptState @@ -21,7 +21,7 @@ [MeasureAs=AsyncClipboardAPIWrite, CallWith=ScriptState, RuntimeEnabled=AsyncClipboard - ] Promise<void> write(Blob data); + ] Promise<void> write(sequence<Blob> data); [MeasureAs=AsyncClipboardAPIWriteText, CallWith=ScriptState
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc index 695497f8..d81079b 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -5,6 +5,8 @@ #include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h" #include <memory> +#include <utility> + #include "base/single_thread_task_runner.h" #include "base/task/post_task.h" #include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h" @@ -38,6 +40,26 @@ // access is gated behind a permission prompt. Both clipboard read and write // require the tab to be focused (and Chromium must be the foreground app) for // the operation to be allowed. +// +// Writing a Blob's data to the system clipboard is accomplished by: +// (1) Reading the blob's contents using a ClipboardFileReader. +// (2) Decoding the blob's contents to avoid RCE in native applications that may +// vulnerabilities in their decoders. +// (3) Writing the blob's decoded contents to the system clipboard. +// +// Reading a type from the system clipboard to a Blob is accomplished by: +// (1) Reading the item from the system clipboard +// (2) Encoding the blob's contents. +// (3) Writing the contents to a blob. +// +// TODO (huangdarwin): Strongly consider making a class break to have +// decoders and encoders in a separate class, with this class mostly checking +// for permissions, and the next class doing decoding/encoding for individual +// types. +// +// TODO (huangdarwin): Use a SequencedTaskRunner to write one clipboard type +// before the next one? This could allow for removing awkward logic regarding +// clipboard_representation_index_. namespace blink { @@ -65,13 +87,15 @@ } ScriptPromise ClipboardPromise::CreateForWrite(ScriptState* script_state, - Blob* data) { + HeapVector<Member<Blob>> data) { ClipboardPromise* clipboard_promise = MakeGarbageCollected<ClipboardPromise>(script_state); + HeapVector<Member<Blob>>* blob_sequence = + MakeGarbageCollected<HeapVector<Member<Blob>>>(data); clipboard_promise->GetTaskRunner()->PostTask( - FROM_HERE, - WTF::Bind(&ClipboardPromise::HandleWrite, - WrapPersistent(clipboard_promise), WrapPersistent(data))); + FROM_HERE, WTF::Bind(&ClipboardPromise::HandleWrite, + WrapPersistent(clipboard_promise), + WrapPersistent(blob_sequence))); return clipboard_promise->script_promise_resolver_->Promise(); } @@ -90,6 +114,7 @@ script_state_(script_state), script_promise_resolver_(ScriptPromiseResolver::Create(script_state)), buffer_(mojom::ClipboardBuffer::kStandard), + clipboard_representation_index_(0), file_reading_task_runner_( GetExecutionContext()->GetTaskRunner(TaskType::kFileReading)) {} @@ -180,24 +205,26 @@ return; } - String type_to_read = TypeToRead(); - Blob* blob = nullptr; - - if (type_to_read == kMimeTypeImagePng) { - blob = ReadImageAsBlob(); - } else if (type_to_read == kMimeTypeTextPlain) { - blob = ReadTextAsBlob(); - } else { - // Reject when there's no data on clipboard. + Vector<String> types_to_read = TypesToRead(); + HeapVector<Member<Blob>> blobs; + blobs.ReserveInitialCapacity(types_to_read.size()); + for (const String& type_to_read : types_to_read) { + if (type_to_read == kMimeTypeImagePng) { + blobs.push_back(ReadImageAsBlob()); + } else if (type_to_read == kMimeTypeTextPlain) { + blobs.push_back(ReadTextAsBlob()); + } else { + NOTREACHED() << "Type " << type_to_read << " was not implemented"; + } } - if (!blob) { + if (!blobs.size()) { script_promise_resolver_->Reject(DOMException::Create( DOMExceptionCode::kDataError, "No valid data on clipboard.")); return; } - script_promise_resolver_->Resolve(std::move(blob)); + script_promise_resolver_->Resolve(std::move(blobs)); } void ClipboardPromise::HandleReadText() { @@ -218,11 +245,11 @@ script_promise_resolver_->Resolve(text); } -// TODO(huangdarwin): This currently only handles plain text and images. -// TODO(huangdarwin): Use an array or structure to hold multiple -// Blobs, like how DataTransfer holds multiple DataTransferItems. -void ClipboardPromise::HandleWrite(Blob* data) { - blob_data_ = data; +void ClipboardPromise::HandleWrite(HeapVector<Member<Blob>>* data) { + // TODO(huangdarwin): This currently only handles plain text and images. + DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); + CHECK(data); + blob_sequence_data_ = std::move(*data); CheckWritePermission(WTF::Bind(&ClipboardPromise::HandleWriteWithPermission, WrapPersistent(this))); @@ -236,17 +263,48 @@ return; } - String type_to_read = blob_data_->type(); - if (type_to_read == kMimeTypeImagePng || type_to_read == kMimeTypeTextPlain) { - DCHECK(!file_reader_); - file_reader_ = std::make_unique<ClipboardFileReader>( - blob_data_, this, file_reading_task_runner_); - } else { - script_promise_resolver_->Reject( - DOMException::Create(DOMExceptionCode::kNotAllowedError, - "Write type " + type_to_read + " not supported.")); + // Check that all blobs have valid and unique MIME types. + HashSet<String> unique_types; + unique_types.ReserveCapacityForSize(blob_sequence_data_.size()); + for (const Member<Blob>& blob : blob_sequence_data_) { + String type = blob->type(); + if (!IsValidClipboardType(type)) { + script_promise_resolver_->Reject( + DOMException::Create(DOMExceptionCode::kNotAllowedError, + "Write type " + type + " not supported.")); + return; + } + if (unique_types.Contains(type)) { + script_promise_resolver_->Reject( + DOMException::Create(DOMExceptionCode::kNotAllowedError, + "Attempting to write duplicate type " + type + + +". All types must be unique")); + } + unique_types.insert(type); + } + + DCHECK(!clipboard_representation_index_); + WriteNextRepresentation(); +} + +// Called to begin writing a type, or after writing each type. +void ClipboardPromise::WriteNextRepresentation() { + DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); + if (clipboard_representation_index_ == blob_sequence_data_.size()) { + SystemClipboard::GetInstance().CommitWrite(); + script_promise_resolver_->Resolve(); return; } + + const Member<Blob>& blob = + blob_sequence_data_[clipboard_representation_index_]; + clipboard_representation_index_++; + DCHECK(IsValidClipboardType(blob->type())); + + // Creates a FileReader to read the Blob. + DCHECK(!file_reader_); + file_reader_ = std::make_unique<ClipboardFileReader>( + blob, this, file_reading_task_runner_); } void ClipboardPromise::HandleWriteText(const String& data) { @@ -264,14 +322,15 @@ return; } - ResolveAndWriteText(write_data_); + SystemClipboard::GetInstance().WritePlainText(write_data_); + script_promise_resolver_->Resolve(); } void ClipboardPromise::OnLoadBufferComplete(DOMArrayBuffer* array_buffer) { + String blob_type = + blob_sequence_data_[clipboard_representation_index_ - 1]->type(); DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); - String blob_type = blob_data_->type(); - DCHECK(blob_type == kMimeTypeImagePng || blob_type == kMimeTypeTextPlain); - + DCHECK(IsValidClipboardType(blob_type)); file_reader_.reset(); if (blob_type == kMimeTypeImagePng) { @@ -286,6 +345,8 @@ CrossThreadBind(&ClipboardPromise::DecodeTextOnBackgroundThread, WrapCrossThreadPersistent(this), GetTaskRunner(), WrapCrossThreadPersistent(array_buffer))); + } else { + NOTREACHED(); } } @@ -322,7 +383,7 @@ PostCrossThreadTask( *task_runner, FROM_HERE, - CrossThreadBind(&ClipboardPromise::ResolveAndWriteImage, + CrossThreadBind(&ClipboardPromise::WriteDecodedImage, WrapCrossThreadPersistent(this), std::move(image))); } @@ -336,25 +397,25 @@ PostCrossThreadTask( *task_runner, FROM_HERE, - CrossThreadBind(&ClipboardPromise::ResolveAndWriteText, + CrossThreadBind(&ClipboardPromise::WriteDecodedText, WrapCrossThreadPersistent(this), std::move(wtf_string))); } -void ClipboardPromise::ResolveAndWriteImage(sk_sp<SkImage> image) { +void ClipboardPromise::WriteDecodedImage(sk_sp<SkImage> image) { DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); SkBitmap bitmap; image->asLegacyBitmap(&bitmap); - SystemClipboard::GetInstance().WriteImage(std::move(bitmap)); - script_promise_resolver_->Resolve(); + SystemClipboard::GetInstance().WriteImageNoCommit(std::move(bitmap)); + WriteNextRepresentation(); } -void ClipboardPromise::ResolveAndWriteText(const String& text) { +void ClipboardPromise::WriteDecodedText(const String& text) { DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); - SystemClipboard::GetInstance().WritePlainText(text); - script_promise_resolver_->Resolve(); + SystemClipboard::GetInstance().WritePlainTextNoCommit(text); + WriteNextRepresentation(); } void ClipboardPromise::Reject() { @@ -365,17 +426,17 @@ // TODO(huangdarwin): This is beginning to share responsibility // with data_object.cc, so how can we share some code? -String ClipboardPromise::TypeToRead() { +Vector<String> ClipboardPromise::TypesToRead() { DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker); - String type_to_read; - for (const String& available_type : - SystemClipboard::GetInstance().ReadAvailableTypes()) { - if (available_type == kMimeTypeImagePng) - return available_type; - if (available_type == kMimeTypeTextPlain) - type_to_read = available_type; + Vector<String> available_types = + SystemClipboard::GetInstance().ReadAvailableTypes(); + Vector<String> types_to_read; + types_to_read.ReserveInitialCapacity(available_types.size()); + for (const String& available_type : available_types) { + if (IsValidClipboardType(available_type)) + types_to_read.push_back(available_type); } - return type_to_read; + return types_to_read; } Blob* ClipboardPromise::ReadTextAsBlob() { @@ -408,10 +469,15 @@ return Blob::Create(png_data.data(), png_data.size(), kMimeTypeImagePng); } +bool ClipboardPromise::IsValidClipboardType(const String& type) { + // TODO (https://crbug.com/931839): Add support for text/html and other types. + return type == kMimeTypeImagePng || type == kMimeTypeTextPlain; +} + void ClipboardPromise::Trace(blink::Visitor* visitor) { visitor->Trace(script_state_); visitor->Trace(script_promise_resolver_); - visitor->Trace(blob_data_); + visitor->Trace(blob_sequence_data_); ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h index 66620930..c093f1b 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h +++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -31,11 +31,13 @@ ClipboardPromise(ScriptState*); virtual ~ClipboardPromise(); + // Creates promise to execute Clipboard API functions off the main thread. static ScriptPromise CreateForRead(ScriptState*); static ScriptPromise CreateForReadText(ScriptState*); - static ScriptPromise CreateForWrite(ScriptState*, Blob*); + static ScriptPromise CreateForWrite(ScriptState*, HeapVector<Member<Blob>>); static ScriptPromise CreateForWriteText(ScriptState*, const String&); + // Entry points back into ClipboardPromise, from ClipboardFileReader. void OnLoadBufferComplete(DOMArrayBuffer*); void Reject(); @@ -43,55 +45,66 @@ private: scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(); - mojom::blink::PermissionService* GetPermissionService(); bool IsFocusedDocument(ExecutionContext*); + // Checks for permissions (interacting with PermissionService). + mojom::blink::PermissionService* GetPermissionService(); void RequestReadPermission( mojom::blink::PermissionService::RequestPermissionCallback); void CheckWritePermission( mojom::blink::PermissionService::HasPermissionCallback); + // Checks Read/Write permission (interacting with PermissionService). void HandleRead(); - void HandleReadWithPermission(mojom::blink::PermissionStatus); - void HandleReadText(); - void HandleReadTextWithPermission(mojom::blink::PermissionStatus); - - void HandleWrite(Blob*); - void HandleWriteWithPermission(mojom::blink::PermissionStatus); - + void HandleWrite(HeapVector<Member<Blob>>*); void HandleWriteText(const String&); + + // Reads/Writes after permission check. + void HandleReadWithPermission(mojom::blink::PermissionStatus); + void HandleReadTextWithPermission(mojom::blink::PermissionStatus); + void HandleWriteWithPermission(mojom::blink::PermissionStatus); void HandleWriteTextWithPermission(mojom::blink::PermissionStatus); + void WriteNextRepresentation(); + + // Decodes for writing. void DecodeImageOnBackgroundThread( scoped_refptr<base::SingleThreadTaskRunner>, DOMArrayBuffer*); void DecodeTextOnBackgroundThread(scoped_refptr<base::SingleThreadTaskRunner>, DOMArrayBuffer*); - void ResolveAndWriteImage(sk_sp<SkImage>); - void ResolveAndWriteText(const String&); + // Writes decoded payload to System Clipboard. + void WriteDecodedImage(sk_sp<SkImage>); + void WriteDecodedText(const String&); - // Detect whether an image or text is on the clipboard. - // Prioritizes image/png over text/plain over none. - String TypeToRead(); + // Detects whether an image or text is on the clipboard, and + // returns all valid clipboard types on the clipboard. + Vector<String> TypesToRead(); - // Get Blob containing System Clipboard contents. + // Gets Blob containing System Clipboard contents. Blob* ReadTextAsBlob(); Blob* ReadImageAsBlob(); - // Because v8 is thread-hostile, ensure that all interactions with ScriptState - // and ScriptPromiseResolver occur on the main thread. + bool IsValidClipboardType(const String&); + + // Because v8 is thread-hostile, ensures that all interactions with + // ScriptState and ScriptPromiseResolver occur on the main thread. Member<ScriptState> script_state_; Member<ScriptPromiseResolver> script_promise_resolver_; + // Reads a Blob's data so that it can be written to the Clipboard. std::unique_ptr<ClipboardFileReader> file_reader_; + // Checks for Read and Write permission. mojom::blink::PermissionServicePtr permission_service_; mojom::ClipboardBuffer buffer_; String write_data_; - Member<Blob> blob_data_; + HeapVector<Member<Blob>> blob_sequence_data_; + // Index of clipboard representation currently being processed. + wtf_size_t clipboard_representation_index_; scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
diff --git a/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc b/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc index c1690f0..ecb9c88 100644 --- a/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc +++ b/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc
@@ -35,7 +35,6 @@ #include "third_party/blink/renderer/core/clipboard/data_transfer_item.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/file.h" -#include "third_party/blink/renderer/modules/filesystem/async_file_system_callbacks.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_path.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc index 8102e31..614d3c6 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc +++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -69,7 +69,7 @@ void DidWrite(int64_t byte_count, bool complete) override { NOTREACHED(); } private: - std::unique_ptr<AsyncFileSystemCallbacks> callbacks_; + std::unique_ptr<EntriesCallbacks> callbacks_; }; FileSystemDispatcher::FileSystemDispatcher(ExecutionContext& context)
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc b/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc index 71b11c1..5d8b699 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
@@ -120,11 +120,11 @@ RTCStatsFilter GetRTCStatsFilter(const ScriptState* script_state) { const ExecutionContext* context = ExecutionContext::From(script_state); DCHECK(context->IsContextThread()); - // If this original trial is enabled then it exposes jitterBufferFlushes - // metric - return origin_trials::RtcAudioJitterBufferMaxPacketsEnabled(context) - ? RTCStatsFilter::kIncludeNonStandardMembers - : RTCStatsFilter::kIncludeOnlyStandardMembers; + if (origin_trials::RtcAudioJitterBufferMaxPacketsEnabled(context) || + origin_trials::RTCStatsRelativePacketArrivalDelayEnabled(context)) { + return RTCStatsFilter::kIncludeNonStandardMembers; + } + return RTCStatsFilter::kIncludeOnlyStandardMembers; } RTCStatsReport::RTCStatsReport(std::unique_ptr<WebRTCStatsReport> report)
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc index a116cf6..7988916a 100644 --- a/third_party/blink/renderer/modules/permissions/permissions.cc +++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -140,11 +140,6 @@ if (name == "payment-handler") return CreatePermissionDescriptor(PermissionName::PAYMENT_HANDLER); if (name == "background-fetch") { - if (!origin_trials::BackgroundFetchEnabled( - ExecutionContext::From(script_state))) { - exception_state.ThrowTypeError("Background Fetch is not enabled."); - return nullptr; - } return CreatePermissionDescriptor(PermissionName::BACKGROUND_FETCH); } if (name == "idle-detection")
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc index d8ea0a16..7ff9a42f 100644 --- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -215,7 +215,8 @@ // JavaScript. void FetchRespondWithObserver::OnResponseRejected( ServiceWorkerResponseError error) { - DCHECK(GetExecutionContext()); + // TODO(crbug.com/934622): Temporary CHECK for the crash bug. + CHECK(GetExecutionContext()); GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( kJSMessageSource, mojom::ConsoleMessageLevel::kWarning, GetMessageForResponseError(error, request_url_))); @@ -234,7 +235,8 @@ ExceptionState::ContextType context_type, const char* interface_name, const char* property_name) { - DCHECK(GetExecutionContext()); + // TODO(crbug.com/934622): Temporary CHECK for the crash bug. + CHECK(GetExecutionContext()); if (!V8Response::HasInstance(value.V8Value(), value.GetIsolate())) { OnResponseRejected(ServiceWorkerResponseError::kNoV8Instance); return;
diff --git a/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc index 216334f6..1e48691 100644 --- a/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc
@@ -18,21 +18,13 @@ namespace blink { -void RespondWithObserver::ContextDestroyed(ExecutionContext*) { - if (observer_) { - DCHECK_EQ(kPending, state_); - observer_.Clear(); - } - state_ = kDone; -} - void RespondWithObserver::WillDispatchEvent() { event_dispatch_time_ = WTF::CurrentTimeTicks(); } void RespondWithObserver::DidDispatchEvent( DispatchEventResult dispatch_result) { - DCHECK(GetExecutionContext()); + CHECK(GetExecutionContext()); if (state_ != kInitial) return; @@ -49,7 +41,7 @@ void RespondWithObserver::RespondWith(ScriptState* script_state, ScriptPromise script_promise, ExceptionState& exception_state) { - if (state_ != kInitial) { + if (state_ != kInitial || !GetExecutionContext()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, "The event has already been responded to."); @@ -88,14 +80,14 @@ RespondWithObserver::RespondWithObserver(ExecutionContext* context, int event_id, WaitUntilObserver* observer) - : ContextLifecycleObserver(context), + : ContextClient(context), event_id_(event_id), state_(kInitial), observer_(observer) {} void RespondWithObserver::Trace(blink::Visitor* visitor) { visitor->Trace(observer_); - ContextLifecycleObserver::Trace(visitor); + ContextClient::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/respond_with_observer.h b/third_party/blink/renderer/modules/service_worker/respond_with_observer.h index 42130eaf..f62f889 100644 --- a/third_party/blink/renderer/modules/service_worker/respond_with_observer.h +++ b/third_party/blink/renderer/modules/service_worker/respond_with_observer.h
@@ -26,14 +26,12 @@ // overriding onResponseFulfilled, onResponseRejected and onNoResponse. class MODULES_EXPORT RespondWithObserver : public GarbageCollectedFinalized<RespondWithObserver>, - public ContextLifecycleObserver { + public ContextClient { USING_GARBAGE_COLLECTED_MIXIN(RespondWithObserver); public: virtual ~RespondWithObserver() = default; - void ContextDestroyed(ExecutionContext*) override; - void WillDispatchEvent(); void DidDispatchEvent(DispatchEventResult dispatch_result);
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc index 473f8b1..f510810f 100644 --- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -111,6 +111,9 @@ } void WaitUntilObserver::WillDispatchEvent() { + // TODO(crbug.com/934622): Temporary CHECK for the crash bug. + CHECK(GetExecutionContext()); + // When handling a notificationclick, paymentrequest, or backgroundfetchclick // event, we want to allow one window to be focused or opened. These calls are // allowed between the call to willDispatchEvent() and the last call to @@ -118,7 +121,7 @@ // between willDispatchEvent() and didDispatchEvent(). if (type_ == kNotificationClick || type_ == kPaymentRequest || type_ == kBackgroundFetchClick) { - execution_context_->AllowWindowInteraction(); + GetExecutionContext()->AllowWindowInteraction(); } DCHECK_EQ(EventDispatchState::kInitial, event_dispatch_state_); @@ -147,7 +150,7 @@ return; } - if (!execution_context_) + if (!GetExecutionContext()) return; // When handling a notificationclick event, we want to allow one window to @@ -195,7 +198,7 @@ WaitUntilObserver::WaitUntilObserver(ExecutionContext* context, EventType type, int event_id) - : execution_context_(context), + : ContextClient(context), type_(type), event_id_(event_id), consume_window_interaction_timer_( @@ -223,7 +226,7 @@ } void WaitUntilObserver::MaybeCompleteEvent() { - if (!execution_context_) + if (!GetExecutionContext()) return; switch (event_dispatch_state_) { @@ -246,7 +249,7 @@ } ServiceWorkerGlobalScopeClient* client = - ServiceWorkerGlobalScopeClient::From(execution_context_); + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()); mojom::ServiceWorkerEventStatus status = (event_dispatch_state_ == EventDispatchState::kFailed || has_rejected_promise_) @@ -269,7 +272,8 @@ client->DidHandleFetchEvent(event_id_, status); break; case kInstall: - To<ServiceWorkerGlobalScope>(*execution_context_).SetIsInstalling(false); + To<ServiceWorkerGlobalScope>(*GetExecutionContext()) + .SetIsInstalling(false); client->DidHandleInstallEvent(event_id_, status); break; case kMessage: @@ -305,17 +309,15 @@ client->DidHandleBackgroundFetchSuccessEvent(event_id_, status); break; } - execution_context_ = nullptr; } void WaitUntilObserver::ConsumeWindowInteraction(TimerBase*) { - if (!execution_context_) - return; - execution_context_->ConsumeWindowInteraction(); + if (ExecutionContext* context = GetExecutionContext()) + context->ConsumeWindowInteraction(); } void WaitUntilObserver::Trace(blink::Visitor* visitor) { - visitor->Trace(execution_context_); + ContextClient::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.h b/third_party/blink/renderer/modules/service_worker/wait_until_observer.h index 2f025fc..a1bd25f2 100644 --- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.h +++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_WAIT_UNTIL_OBSERVER_H_ #include "base/callback.h" +#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" #include "third_party/blink/renderer/platform/timer.h" @@ -14,14 +15,16 @@ namespace blink { class ExceptionState; -class ExecutionContext; class ScriptPromise; class ScriptState; class ScriptValue; // Created for each ExtendableEvent instance. class MODULES_EXPORT WaitUntilObserver final - : public GarbageCollectedFinalized<WaitUntilObserver> { + : public GarbageCollectedFinalized<WaitUntilObserver>, + public ContextClient { + USING_GARBAGE_COLLECTED_MIXIN(WaitUntilObserver); + public: using PromiseSettledCallback = base::RepeatingCallback<void(const ScriptValue&)>; @@ -75,7 +78,7 @@ // https://w3c.github.io/ServiceWorker/#extendableevent-active. bool IsEventActive(ScriptState* script_state) const; - virtual void Trace(blink::Visitor*); + void Trace(blink::Visitor*) override; private: friend class InternalsServiceWorker; @@ -108,7 +111,6 @@ void MaybeCompleteEvent(); - Member<ExecutionContext> execution_context_; EventType type_; int event_id_; int pending_promises_ = 0;
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc b/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc index 2060b0a7..13b20ce 100644 --- a/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc +++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc
@@ -16,19 +16,59 @@ namespace blink { +namespace { + +WebString BarcodeFormatToString( + const shape_detection::mojom::blink::BarcodeFormat format) { + switch (format) { + case shape_detection::mojom::blink::BarcodeFormat::AZTEC: + return WebString::FromUTF8("aztec"); + case shape_detection::mojom::blink::BarcodeFormat::CODE_128: + return WebString::FromUTF8("code_128"); + case shape_detection::mojom::blink::BarcodeFormat::CODE_39: + return WebString::FromUTF8("code_39"); + case shape_detection::mojom::blink::BarcodeFormat::CODE_93: + return WebString::FromUTF8("code_93"); + case shape_detection::mojom::blink::BarcodeFormat::CODABAR: + return WebString::FromUTF8("codabar"); + case shape_detection::mojom::blink::BarcodeFormat::DATA_MATRIX: + return WebString::FromUTF8("data_matrix"); + case shape_detection::mojom::blink::BarcodeFormat::EAN_13: + return WebString::FromUTF8("ean_13"); + case shape_detection::mojom::blink::BarcodeFormat::EAN_8: + return WebString::FromUTF8("ean_8"); + case shape_detection::mojom::blink::BarcodeFormat::ITF: + return WebString::FromUTF8("itf"); + case shape_detection::mojom::blink::BarcodeFormat::PDF417: + return WebString::FromUTF8("pdf417"); + case shape_detection::mojom::blink::BarcodeFormat::QR_CODE: + return WebString::FromUTF8("qr_code"); + case shape_detection::mojom::blink::BarcodeFormat::UNKNOWN: + return WebString::FromUTF8("unknown"); + case shape_detection::mojom::blink::BarcodeFormat::UPC_A: + return WebString::FromUTF8("upc_a"); + case shape_detection::mojom::blink::BarcodeFormat::UPC_E: + return WebString::FromUTF8("upc_e"); + default: + NOTREACHED() << "Invalid BarcodeFormat"; + } + return WebString(); +} + +} // namespace + BarcodeDetector* BarcodeDetector::Create(ExecutionContext* context) { return MakeGarbageCollected<BarcodeDetector>(context); } BarcodeDetector::BarcodeDetector(ExecutionContext* context) : ShapeDetector() { - shape_detection::mojom::blink::BarcodeDetectionProviderPtr provider; // See https://bit.ly/2S0zRAS for task types. auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI); - auto request = mojo::MakeRequest(&provider, task_runner); + auto request = mojo::MakeRequest(&barcode_provider_, task_runner); if (auto* interface_provider = context->GetInterfaceProvider()) { interface_provider->GetInterface(std::move(request)); } - provider->CreateBarcodeDetection( + barcode_provider_->CreateBarcodeDetection( mojo::MakeRequest(&barcode_service_, task_runner), shape_detection::mojom::blink::BarcodeDetectorOptions::New()); @@ -37,6 +77,40 @@ WrapWeakPersistent(this))); } +ScriptPromise BarcodeDetector::getSupportedFormats(ScriptState* script_state) { + ExecutionContext* context = ExecutionContext::From(script_state); + BarcodeDetector* detector = BarcodeDetector::Create(context); + + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise promise = resolver->Promise(); + if (!detector->barcode_service_) { + resolver->Reject( + DOMException::Create(DOMExceptionCode::kNotSupportedError, + "Barcode detection service unavailable.")); + return promise; + } + + detector->barcode_service_requests_.insert(resolver); + detector->barcode_provider_->EnumerateSupportedFormats( + WTF::Bind(&BarcodeDetector::OnEnumerateSupportedFormats, + WrapPersistent(detector), WrapPersistent(resolver))); + return promise; +} + +void BarcodeDetector::OnEnumerateSupportedFormats( + ScriptPromiseResolver* resolver, + const Vector<shape_detection::mojom::blink::BarcodeFormat>& + format_results) { + DCHECK(barcode_service_requests_.Contains(resolver)); + barcode_service_requests_.erase(resolver); + + Vector<WTF::String> formats; + formats.ReserveInitialCapacity(format_results.size()); + for (const auto& format : format_results) + formats.push_back(BarcodeFormatToString(format)); + resolver->Resolve(formats); +} + ScriptPromise BarcodeDetector::DoDetect(ScriptPromiseResolver* resolver, SkBitmap bitmap) { ScriptPromise promise = resolver->Promise(); @@ -88,6 +162,7 @@ } barcode_service_requests_.clear(); barcode_service_.reset(); + barcode_provider_.reset(); } void BarcodeDetector::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector.h b/third_party/blink/renderer/modules/shapedetection/barcode_detector.h index d596079..5ad4870d 100644 --- a/third_party/blink/renderer/modules/shapedetection/barcode_detector.h +++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_BARCODE_DETECTOR_H_ #include "services/shape_detection/public/mojom/barcodedetection.mojom-blink.h" +#include "services/shape_detection/public/mojom/barcodedetection_provider.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h" @@ -22,6 +23,9 @@ public: static BarcodeDetector* Create(ExecutionContext*); + // Barcode Detection API functions. + static ScriptPromise getSupportedFormats(ScriptState*); + explicit BarcodeDetector(ExecutionContext*); void Trace(blink::Visitor*) override; @@ -29,13 +33,19 @@ private: ~BarcodeDetector() override = default; + void OnEnumerateSupportedFormats( + ScriptPromiseResolver*, + const Vector<shape_detection::mojom::blink::BarcodeFormat>&); + ScriptPromise DoDetect(ScriptPromiseResolver*, SkBitmap) override; void OnDetectBarcodes( ScriptPromiseResolver*, Vector<shape_detection::mojom::blink::BarcodeDetectionResultPtr>); + void OnBarcodeServiceConnectionError(); shape_detection::mojom::blink::BarcodeDetectionPtr barcode_service_; + shape_detection::mojom::blink::BarcodeDetectionProviderPtr barcode_provider_; HeapHashSet<Member<ScriptPromiseResolver>> barcode_service_requests_; };
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl b/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl index 47ac42c..4e9b0e5 100644 --- a/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl +++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl
@@ -11,5 +11,6 @@ MeasureAs=ShapeDetection_BarcodeDetectorConstructor, RuntimeEnabled=ShapeDetection ] interface BarcodeDetector { + [CallWith=ScriptState] static Promise<sequence<BarcodeFormat>> getSupportedFormats(); [CallWith=ScriptState, MeasureAs=ShapeDetectionAPI] Promise<sequence<DetectedBarcode>> detect(ImageBitmapSource image); };
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc index 1bbfb4a..1e37c86f 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.cc +++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -50,6 +50,15 @@ constexpr WTF::TimeDelta kNonImmersivePoseAgeThreshold = WTF::TimeDelta::FromMilliseconds(250); +device::mojom::blink::XRFrameDataPtr CreateIdentityFrameData() { + auto data = device::mojom::blink::XRFrameData::New(); + data->pose = device::mojom::blink::VRPose::New(); + data->pose->orientation.emplace({0.0f, 0.0f, 0.0f, 1.0f}); + data->pose->position.emplace({0.0f, 0.0f, 0.0f}); + + return data; +} + VREye StringToVREye(const String& which_eye) { if (which_eye == "left") return kVREyeLeft; @@ -279,18 +288,28 @@ DVLOG(2) << __FUNCTION__ << " done: pending_presenting_vsync_=" << pending_presenting_vsync_; } else { - // Check if non_immersive_provider_, if not then we are not fully - // initialized, or we do not support non-immersive, so don't request the - // vsync. If and when non_immersive_provider_ is set it will run this code - // again. - if (!non_immersive_provider_) + // If we haven't been fully initialized yet, then we need to keep waiting + // so that we know if we have a non immersive provider or if we need to + // pass out identity poses. When the callback from initialization happens + // it will run this code again. + if (!non_immersive_session_initialized_) return; if (pending_non_immersive_vsync_) return; non_immersive_vsync_waiting_for_pose_.Reset(); non_immersive_pose_request_time_ = WTF::CurrentTimeTicks(); - non_immersive_provider_->GetFrameData(WTF::Bind( - &VRDisplay::OnNonImmersiveFrameData, WrapWeakPersistent(this))); + + if (non_immersive_provider_) { + non_immersive_provider_->GetFrameData(WTF::Bind( + &VRDisplay::OnNonImmersiveFrameData, WrapWeakPersistent(this))); + } else { + // If we don't have a non immersive provider, we should just return + // an identity pose. We're not worried about re-entrant calls right now + // because we should end up waiting for the RAF callback which we request + // below. If we start to see errors with this, we'll want to do this as a + // posted task. + OnNonImmersiveFrameData(CreateIdentityFrameData()); + } pending_non_immersive_vsync_ = true; pending_non_immersive_vsync_id_ = doc->RequestAnimationFrame( MakeGarbageCollected<VRDisplayFrameRequestCallback>(this)); @@ -586,14 +605,20 @@ void VRDisplay::OnNonImmersiveSessionRequestReturned( device::mojom::blink::XRSessionPtr session) { - if (!session) { - // System does not support any kind of session. - return; + non_immersive_session_initialized_ = true; + + // Only create the non immersive provider if we actually got a session. + // If we didn't get a session, we will just hand out identity poses. + if (session) { + non_immersive_provider_.Bind(std::move(session->data_provider)); + non_immersive_client_binding_ = MakeGarbageCollected<SessionClientBinding>( + this, SessionClientBinding::SessionBindingType::kNonImmersive, + std::move(session->client_request)); } - non_immersive_provider_.Bind(std::move(session->data_provider)); - non_immersive_client_binding_ = MakeGarbageCollected<SessionClientBinding>( - this, SessionClientBinding::SessionBindingType::kNonImmersive, - std::move(session->client_request)); + + // Now that we're initialized, we need to ensure that the data is flowing + // by requesting a VSync, since it may have skipped requesting one because + // we weren't yet initialized. RequestVSync(); }
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h index 8c19d5dd..94a20fc 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.h +++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -259,6 +259,7 @@ bool did_log_getFrameData_ = false; bool did_log_requestPresent_ = false; + bool non_immersive_session_initialized_ = false; device::mojom::blink::XRFrameDataProviderPtr non_immersive_provider_; device::mojom::blink::XRDevicePtr device_ptr_;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl index 48dfa39..9cd92a0f 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl +++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl
@@ -48,6 +48,7 @@ const GLenum TRANSFORM_FEEDBACK_BARRIER_BIT = 0x00000800; const GLenum ATOMIC_COUNTER_BARRIER_BIT = 0x00001000; const GLenum SHADER_STORAGE_BARRIER_BIT = 0x00002000; + const GLenum ALL_BARRIER_BITS = 0xFFFFFFFF; const GLenum FALSE = 0; const GLenum TRUE = 1; const GLenum READ_ONLY = 0x88B8;
diff --git a/third_party/blink/renderer/modules/websockets/README.md b/third_party/blink/renderer/modules/websockets/README.md index a8e8f54..16b973ad 100644 --- a/third_party/blink/renderer/modules/websockets/README.md +++ b/third_party/blink/renderer/modules/websockets/README.md
@@ -7,3 +7,14 @@ They use WebSocketChannelImpl to connect to the WebSocket service i.e. the blink.mojom.WebSocket implementation in content/browser/websockets/. + +## Design docs + +See also [//net/websockets/README.md](../../../../../net/websockets/README.md) +for the design of the network service side of the implementation. + +* [WebSocket SafeBrowsing + Support](https://docs.google.com/document/d/1iR3XMIQukqlXb6ajIHE91apHZAxyF_wvRoB5JGeJYPs/edit) + describes how SafeBrowsing checks are done on WebSocket URLs. Some class names + and details have changed as Worker WebSockets are no longer proxies via the + main thread.
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index ef7a4f44..9768856 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -265,11 +265,7 @@ void XR::DispatchRequestSession(PendingSessionQuery* query) { if (!device_) { if (query->mode == XRSession::kModeInline) { - XRSession* session = MakeGarbageCollected<XRSession>( - this, nullptr /* client request */, query->mode, - XRSession::kBlendModeOpaque); - sessions_.insert(session); - query->resolver->Resolve(session); + CreateInlineIdentitySession(query); return; } @@ -370,6 +366,11 @@ // TODO(https://crbug.com/872316) Improve the error messaging to indicate why // a request failed. if (!session_ptr) { + if (query->mode == XRSession::kModeInline) { + CreateInlineIdentitySession(query); + return; + } + DOMException* exception = DOMException::Create( DOMExceptionCode::kNotSupportedError, kSessionNotSupported); query->resolver->Reject(exception); @@ -448,6 +449,14 @@ Dispose(); } +void XR::CreateInlineIdentitySession(PendingSessionQuery* query) { + XRSession* session = + MakeGarbageCollected<XRSession>(this, nullptr /* client request */, + query->mode, XRSession::kBlendModeOpaque); + sessions_.insert(session); + query->resolver->Resolve(session); +} + void XR::Dispose() { // If the document context was destroyed, shut down the client connection // and never call the mojo service again.
diff --git a/third_party/blink/renderer/modules/xr/xr.h b/third_party/blink/renderer/modules/xr/xr.h index 7a936861..1e7719e 100644 --- a/third_party/blink/renderer/modules/xr/xr.h +++ b/third_party/blink/renderer/modules/xr/xr.h
@@ -103,6 +103,8 @@ void AddedEventListener(const AtomicString& event_type, RegisteredEventListener&) override; + void CreateInlineIdentitySession(PendingSessionQuery*); + void Dispose(); bool pending_device_ = false;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index 70eb402..e1b4176 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -155,7 +155,13 @@ // TODO(jacde): Update the mojom to deliver this per-frame. bool EmulatedPosition() const { - return !display_info_->capabilities->hasPosition; + if (display_info_) { + return !display_info_->capabilities->hasPosition; + } + + // If we don't have display info then we should be using the identity + // reference space, which by definition will be emulating the position. + return true; } void UpdateDisplayInfo(
diff --git a/third_party/blink/renderer/platform/geometry/calculation_value.h b/third_party/blink/renderer/platform/geometry/calculation_value.h index 24c7ae0..99594ea 100644 --- a/third_party/blink/renderer/platform/geometry/calculation_value.h +++ b/third_party/blink/renderer/platform/geometry/calculation_value.h
@@ -34,11 +34,14 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/platform/geometry/length.h" #include "third_party/blink/renderer/platform/geometry/length_functions.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" namespace blink { class PLATFORM_EXPORT CalculationValue : public RefCounted<CalculationValue> { + USING_FAST_MALLOC(CalculationValue); + public: static scoped_refptr<CalculationValue> Create(PixelsAndPercent value, ValueRange range) {
diff --git a/third_party/blink/renderer/platform/geometry/float_polygon_test.cc b/third_party/blink/renderer/platform/geometry/float_polygon_test.cc index 03aac2d3b..5919b57 100644 --- a/third_party/blink/renderer/platform/geometry/float_polygon_test.cc +++ b/third_party/blink/renderer/platform/geometry/float_polygon_test.cc
@@ -34,10 +34,13 @@ #include <utility> #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink { class FloatPolygonTestValue { + STACK_ALLOCATED(); + public: FloatPolygonTestValue(const float* coordinates, unsigned coordinates_length) { DCHECK(!(coordinates_length % 2));
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc index 28e17efa..51b99aa 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -1586,22 +1586,13 @@ GLuint rgb_texture = back_color_buffer_->rgb_workaround_texture_id; DCHECK_EQ(texture_target_, GC3D_TEXTURE_RECTANGLE_ARB); if (!rgb_texture) { - gpu::SharedImageInterface* sii = ContextProvider()->SharedImageInterface(); - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = - Platform::Current()->GetGpuMemoryBufferManager(); - back_color_buffer_->rgb_workaround_mailbox = sii->CreateSharedImage( - back_color_buffer_->gpu_memory_buffer.get(), gpu_memory_buffer_manager, - storage_color_space_, - gpu::SHARED_IMAGE_USAGE_GLES2 | - gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT | - gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT | - gpu::SHARED_IMAGE_USAGE_RGB_EMULATION); - gl_->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); - rgb_texture = gl_->CreateAndTexStorage2DSharedImageCHROMIUM( - back_color_buffer_->rgb_workaround_mailbox.name); + rgb_texture = + gl_->CreateAndTexStorage2DSharedImageWithInternalFormatCHROMIUM( + back_color_buffer_->mailbox.name, GL_RGB); back_color_buffer_->rgb_workaround_texture_id = rgb_texture; } + gl_->EndSharedImageAccessDirectCHROMIUM(back_color_buffer_->texture_id); gl_->BeginSharedImageAccessDirectCHROMIUM( rgb_texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER_ANGLE, GL_COLOR_ATTACHMENT0, @@ -1616,6 +1607,9 @@ DCHECK(back_color_buffer_->gpu_memory_buffer); gl_->EndSharedImageAccessDirectCHROMIUM( back_color_buffer_->rgb_workaround_texture_id); + gl_->BeginSharedImageAccessDirectCHROMIUM( + back_color_buffer_->texture_id, + GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER_ANGLE, GL_COLOR_ATTACHMENT0, texture_target_, back_color_buffer_->texture_id, 0); // Clear the alpha channel.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 2bcf056..733effae 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -138,8 +138,7 @@ }, { name: "BackgroundFetch", - origin_trial_feature_name: "BackgroundFetch", - status: "experimental", + status: "stable", }, { name: "BackgroundVideoTrackOptimization", @@ -155,7 +154,7 @@ }, { name: "BlinkGenPropertyTrees", - status: "stable", + status: "experimental", }, { name: "BlinkRuntimeCallStats", @@ -1213,6 +1212,11 @@ name: "RTCRtpSenderParameters", status: "stable", }, + { + name: "RTCStatsRelativePacketArrivalDelay", + origin_trial_feature_name: "RTCStatsRelativePacketArrivalDelay", + status: "experimental", + }, // Enables the use of |RTCConfiguration::sdpSemantics| to override the // default SDP semantics at RTCPeerConnection construction. {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index 4c99f80..23d6a3a 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -817,6 +817,12 @@ if (fixed_priority) return fixed_priority.value(); + if (!parent_page_scheduler_) { + // Frame might be detached during its shutdown. Return a default priority + // in that case. + return TaskQueue::QueuePriority::kNormalPriority; + } + // A hidden page with no audio. if (parent_page_scheduler_->IsBackgrounded()) { if (main_thread_scheduler_->scheduling_settings()
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index a889e8f..50e65225 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -1850,6 +1850,13 @@ task_queue->FixedPriority().value()); } +TEST_F(FrameSchedulerImplTest, ComputePriorityForDetachedFrame) { + auto task_queue = GetTaskQueue(TaskType::kJavascriptTimer); + // Just check that it does not crash. + page_scheduler_.reset(); + frame_scheduler_->ComputePriority(task_queue.get()); +} + } // namespace frame_scheduler_impl_unittest } // namespace scheduler } // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/sequence_manager_fuzzer_processor.h b/third_party/blink/renderer/platform/scheduler/test/fuzzer/sequence_manager_fuzzer_processor.h index a150d20f..c5b156da 100644 --- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/sequence_manager_fuzzer_processor.h +++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/sequence_manager_fuzzer_processor.h
@@ -26,7 +26,7 @@ // by the |thread_pool_manager_| should live for the scope of the main thread // entry function i.e RunTest. class PLATFORM_EXPORT SequenceManagerFuzzerProcessor { - DISALLOW_NEW(); + USING_FAST_MALLOC(SequenceManagerFuzzerProcessor); public: // Public interface used to parse the fuzzer's test description and
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index b07140a..e60135a 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -1727,8 +1727,10 @@ external/wpt/battery-status/battery-charging-manual.https.html [ WontFix ] external/wpt/battery-status/battery-plugging-in-manual.https.html [ WontFix ] external/wpt/battery-status/battery-unplugging-manual.https.html [ WontFix ] +external/wpt/clipboard-apis/async-write-blobs-read-blobs-manual.https.html [ WontFix ] external/wpt/clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html [ WontFix ] external/wpt/clipboard-apis/async-write-blobtext-read-text-manual.https.html [ WontFix ] +external/wpt/clipboard-apis/async-write-duplicate-mime-type-manual.https.html [ WontFix ] external/wpt/clipboard-apis/async-write-image-read-image-manual.https.html [ WontFix ] external/wpt/clipboard-apis/async-write-text-read-blobtext-manual.https.html [ WontFix ] external/wpt/clipboard-apis/async-write-text-read-text-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 9222235..b3df8d3 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2903,6 +2903,8 @@ crbug.com/723741 virtual/threaded/http/tests/devtools/tracing/idle-callback.js [ Failure Crash Pass Timeout ] +# Sheriff 2019-03-07 +crbug.com/939406 external/wpt/html/browsers/windows/embedded-opener-remove-frame.html [ Failure ] # Untriaged failures after https://crrev.com/c/543695/. # These need to be updated but appear not to be related to that change. @@ -2934,7 +2936,7 @@ # Failure messages are unstable so we cannot create baselines. crbug.com/832071 external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] -crbug.com/832071 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] +crbug.com/832071 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Timeout ] crbug.com/832071 virtual/outofblink-cors/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] # failures in external/wpt/css/css-animations/ and web-animations/ from Mozilla tests @@ -3032,8 +3034,9 @@ crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ] # ====== New tests from wpt-importer added here ====== -crbug.com/626703 [ Mac10.10 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ] -crbug.com/626703 [ Mac10.11 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ] +crbug.com/626703 external/wpt/css/css-sizing/range-percent-intrinsic-size-2a.html [ Failure ] +crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy.html [ Failure ] +crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_1.html [ Failure ] crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ] crbug.com/626703 external/wpt/html/semantics/forms/the-fieldset-element/accessibility/fieldset-div-display-contents-manual.html [ Skip ] crbug.com/626703 external/wpt/html/semantics/forms/the-fieldset-element/accessibility/role-manual.html [ Skip ] @@ -3183,7 +3186,7 @@ crbug.com/626703 external/wpt/svg/painting/marker-005.svg [ Failure ] crbug.com/626703 [ Linux ] external/wpt/css/css-variables/variable-exponential-blowup.html [ Timeout Crash ] crbug.com/626703 [ Mac ] external/wpt/css/css-variables/variable-exponential-blowup.html [ Timeout ] -crbug.com/626703 [ Win ] external/wpt/css/css-variables/variable-exponential-blowup.html [ Crash ] +crbug.com/626703 [ Win ] external/wpt/css/css-variables/variable-exponential-blowup.html [ Timeout Crash ] crbug.com/626703 [ Mac10.13 ] external/wpt/preload/dynamic-adding-preload-imagesrcset.tentative.html [ Timeout ] crbug.com/906369 external/wpt/css/css-text/text-transform/text-transform-capitalize-033.html [ Failure ] crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/content-type/response.window.html [ Timeout ] @@ -4214,6 +4217,14 @@ # This fails because off-the-main-thread script loading goes through different # loading path. Although we could remove this test. disable it for now. crbug.com/835717 virtual/omt-worker-fetch/fast/workers/chromium/worker-crash-with-invalid-location.html [ Skip ] +# Needs investigation. These are timing out. +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/clients-get-client-types.https.html [ Skip ] +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-request-xhr-sync-on-worker.https.html [ Skip ] +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Skip ] +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Skip ] +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/worker-interception.https.html [ Skip ] +# This is crashing because of DCHECK. +crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/dedicated-worker-service-worker-interception.https.html [ Skip ] # This fails because AllowedByNoSniff::MimeTypeAsScript() blocks the nested worker's # worker script, because the script url has a .html file extension. @@ -4746,6 +4757,7 @@ crbug.com/669329 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ] crbug.com/799619 [ Debug ] http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Pass Timeout ] +crbug.com/939037 [ Win7 ] http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ] crbug.com/939037 [ Mac Linux ] http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ] crbug.com/769347 [ Mac ] fast/dom/inert/inert-node-is-uneditable.html [ Failure ] @@ -5985,8 +5997,7 @@ crbug.com/936827 external/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html [ Failure Pass ] # Enable WPT animation-worklet test to run with threaded-compositing -crbug.com/915352 virtual/threaded/external/wpt/animation-worklet/playback-rate.https.html [ Pass Failure ] -crbug.com/915352 [ Linux ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-pause-resume.https.html [ Pass Failure ] +crbug.com/915352 virtual/threaded/external/wpt/animation-worklet/worklet-animation-pause-resume.https.html [ Pass Failure ] crbug.com/915352 [ Mac10.10 Mac10.11 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline.https.html [ Pass Failure ] crbug.com/915352 [ Mac10.10 Mac10.11 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html [ Pass Failure ] @@ -6016,8 +6027,12 @@ # Sheriff 2019-03-05 crbug.com/938200 http/tests/devtools/network/network-blocked-reason.js [ Timeout Pass ] -crbug.com/938780 [ Mac ] external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ] +crbug.com/938780 [ Mac ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ] # Sheriff 2019-03-06 crbug.com/938591 [ Linux ] fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Failure Pass ] crbug.com/938884 [ Win7 Mac ] http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ] + +# Caused a revert of a good change. +crbug.com/931533 media/video-played-collapse.html [ Pass Failure ] +crbug.com/931533 virtual/video-surface-layer/media/video-played-collapse.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 09b2651a..880925d 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -622,7 +622,7 @@ { "prefix": "omt-worker-fetch", "base": "external/wpt/service-workers", - "args": ["--enable-features=OffMainThreadServiceWorkerScriptFetch"] + "args": ["--enable-features=OffMainThreadDedicatedWorkerScriptFetch,PlzDedicatedWorker,OffMainThreadServiceWorkerScriptFetch,OffMainThreadSharedWorkerScriptFetch"] }, { "prefix": "omt-worker-fetch",
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/async-navigator-clipboard-basics.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/async-navigator-clipboard-basics.https.html index bb00bb9..618bdf76 100644 --- a/third_party/blink/web_tests/clipboard/async-clipboard/async-navigator-clipboard-basics.https.html +++ b/third_party/blink/web_tests/clipboard/async-clipboard/async-navigator-clipboard-basics.https.html
@@ -18,34 +18,29 @@ assert_equals(navigator.clipboard, navigator.clipboard); }, "navigator.clipboard exists"); -/* clipboard.write(text/plain Blob) */ - promise_test(async () => { await getPermissions(); const blob = new Blob(["hello"], {type: 'text/plain'}); - await navigator.clipboard.write(blob); -}, "navigator.clipboard.write(text/plain Blob) succeeds"); + await navigator.clipboard.write([blob]); +}, "navigator.clipboard.write([text/plain Blob]) succeeds"); promise_test(async t => { await getPermissions(); await promise_rejects(t, new TypeError(), navigator.clipboard.write()); -}, "navigator.clipboard.write() fails (expect Blob)"); +}, "navigator.clipboard.write() fails (expect [Blob])"); promise_test(async t => { await getPermissions(); await promise_rejects(t, new TypeError(), navigator.clipboard.write(null)); -}, "navigator.clipboard.write(null) fails (expect Blob)"); +}, "navigator.clipboard.write(null) fails (expect [Blob])"); promise_test(async t => { await getPermissions(); await promise_rejects(t, new TypeError(), navigator.clipboard.write("Bad string")); -}, "navigator.clipboard.write(DOMString) fails (expect Blob)"); - - -/* clipboard.writeText() */ +}, "navigator.clipboard.write(DOMString) fails (expect [Blob])"); promise_test(async () => { await getPermissions(); @@ -58,18 +53,14 @@ navigator.clipboard.writeText()); }, "navigator.clipboard.writeText() fails (expect DOMString)"); -/* text/plain or image/png Blob clipboard.read() */ - promise_test(async () => { await getPermissions(); const result = await navigator.clipboard.read(); - assert_true(result instanceof Blob); + assert_true(result instanceof Array); + assert_true(result[0] instanceof Blob); assert_equals(typeof result, "object"); }, "navigator.clipboard.read() succeeds"); - -/* clipboard.readText() */ - promise_test(async () => { await getPermissions(); const result = await navigator.clipboard.readText();
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-blobtext.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-blobtext.https.html index 7aadc20..7be86d9 100644 --- a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-blobtext.https.html +++ b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-blobtext.https.html
@@ -1,6 +1,8 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard write (text/plain Blob) -> read (text/plain Blob) tests</title> +<title> + Async Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) tests +</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../../http/tests/resources/permissions-helper.js"></script> @@ -12,8 +14,10 @@ const blobInput = new Blob([textInput], {type: 'text/plain'}); - await navigator.clipboard.write(blobInput); - const blobOutput = await navigator.clipboard.read(); + await navigator.clipboard.write([blobInput]); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; assert_equals(blobOutput.type, "text/plain"); const textOutput = await (new Response(blobOutput)).text(); @@ -21,6 +25,6 @@ }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write (text/plain Blob) -> read (text/plain Blob) test"); +readWriteTest("Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) test"); readWriteTest("non-Latin1 text encoding test データ"); </script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-text.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-text.https.html index 1305e5b..62e73a0 100644 --- a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-text.https.html +++ b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-blobtext-read-text.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard write (text/plain Blob) -> readText tests</title> +<title>Async Clipboard write ([text/plain Blob]) -> readText tests</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../../http/tests/resources/permissions-helper.js"></script> @@ -12,13 +12,13 @@ const blobInput = new Blob([textInput], {type: 'text/plain'}); - await navigator.clipboard.write(blobInput); + await navigator.clipboard.write([blobInput]); const textOutput = await navigator.clipboard.readText(); assert_equals(textOutput, textInput); }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write (text/plain Blob) -> read text test"); +readWriteTest("Clipboard write ([text/plain Blob]) -> read text test"); readWriteTest("non-Latin1 text encoding test データ"); </script>
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-duplicate-mime-type.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-duplicate-mime-type.https.html new file mode 100644 index 0000000..1d54dd4 --- /dev/null +++ b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-duplicate-mime-type.https.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Async Clipboard write duplicate mime type test +</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../http/tests/resources/permissions-helper.js"></script> + +<script> +promise_test(async t => { + await PermissionsHelper.setPermission('clipboard-write', 'granted'); + + const blobText = new Blob(["test text"], {type: 'text/plain'}); + const blobText2 = new Blob(["test text"], {type: 'text/plain'}); + + assert_equals(blobText.type, "text/plain"); + assert_equals(blobText2.type, "text/plain"); + + await promise_rejects(t, 'NotAllowedError', + navigator.clipboard.write([blobText, blobText2])); +}, "Verify write and read clipboard (multiple blobs)"); +</script>
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-text-read-blobtext.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-text-read-blobtext.https.html index c896aa1..2dfeb5d9 100644 --- a/third_party/blink/web_tests/clipboard/async-clipboard/async-write-text-read-blobtext.https.html +++ b/third_party/blink/web_tests/clipboard/async-clipboard/async-write-text-read-blobtext.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard writeText -> read (text/plain Blob) tests</title> +<title>Async Clipboard writeText -> read ([text/plain Blob]) tests</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../../http/tests/resources/permissions-helper.js"></script> @@ -11,7 +11,9 @@ await PermissionsHelper.setPermission('clipboard-write', 'granted'); await navigator.clipboard.writeText(textInput); - const blobOutput = await navigator.clipboard.read(); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; assert_equals(blobOutput.type, "text/plain"); const textOutput = await (new Response(blobOutput)).text(); @@ -19,6 +21,6 @@ }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write text -> read (text/plain Blob) test"); +readWriteTest("Clipboard write text -> read ([text/plain Blob]) test"); readWriteTest("non-Latin1 text encoding test データ"); </script>
diff --git a/third_party/blink/web_tests/clipboard/async-clipboard/writetext-denied.https.html b/third_party/blink/web_tests/clipboard/async-clipboard/writetext-denied.https.html index 04ce46c..4a0f6ed 100644 --- a/third_party/blink/web_tests/clipboard/async-clipboard/writetext-denied.https.html +++ b/third_party/blink/web_tests/clipboard/async-clipboard/writetext-denied.https.html
@@ -7,6 +7,6 @@ <script> promise_test(async t => { await PermissionsHelper.setPermission('clipboard-write', 'denied'); - await promise_rejects(t, 'NotAllowedError', navigator.clipboard.readText()); + await promise_rejects(t, 'NotAllowedError', navigator.clipboard.writeText("xyz")); }, "navigator.clipboard.writeText() fails when permission denied"); </script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json index 379450c..eacba0e 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -60111,6 +60111,18 @@ {} ] ], + "css/css-sizing/range-percent-intrinsic-size-2a.html": [ + [ + "/css/css-sizing/range-percent-intrinsic-size-2a.html", + [ + [ + "/css/css-sizing/range-percent-intrinsic-size-2a-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-sizing/whitespace-and-break.html": [ [ "/css/css-sizing/whitespace-and-break.html", @@ -60819,6 +60831,18 @@ {} ] ], + "css/css-text-decor/text-decoration-propagation-shadow.html": [ + [ + "/css/css-text-decor/text-decoration-propagation-shadow.html", + [ + [ + "/css/css-text-decor/reference/text-decoration-underline-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text-decor/text-decoration-style-multiple.html": [ [ "/css/css-text-decor/text-decoration-style-multiple.html", @@ -93387,6 +93411,378 @@ {} ] ], + "css/filter-effects/tainting-feblend-001.html": [ + [ + "/css/filter-effects/tainting-feblend-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feblend-002.html": [ + [ + "/css/filter-effects/tainting-feblend-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fecomponenttransfer-001.html": [ + [ + "/css/filter-effects/tainting-fecomponenttransfer-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fecomponenttransfer-002.html": [ + [ + "/css/filter-effects/tainting-fecomponenttransfer-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fecomposite-001.html": [ + [ + "/css/filter-effects/tainting-fecomposite-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fecomposite-002.html": [ + [ + "/css/filter-effects/tainting-fecomposite-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feconvolvematrix-001.html": [ + [ + "/css/filter-effects/tainting-feconvolvematrix-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feconvolvematrix-002.html": [ + [ + "/css/filter-effects/tainting-feconvolvematrix-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fediffuselighting-001.html": [ + [ + "/css/filter-effects/tainting-fediffuselighting-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fediffuselighting-002.html": [ + [ + "/css/filter-effects/tainting-fediffuselighting-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fediffuselighting-003.html": [ + [ + "/css/filter-effects/tainting-fediffuselighting-003.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fediffuselighting-dynamic.html": [ + [ + "/css/filter-effects/tainting-fediffuselighting-dynamic.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fedisplacementmap-001.html": [ + [ + "/css/filter-effects/tainting-fedisplacementmap-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fedisplacementmap-002.html": [ + [ + "/css/filter-effects/tainting-fedisplacementmap-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fedropshadow-001.html": [ + [ + "/css/filter-effects/tainting-fedropshadow-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fedropshadow-002.html": [ + [ + "/css/filter-effects/tainting-fedropshadow-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fedropshadow-003.html": [ + [ + "/css/filter-effects/tainting-fedropshadow-003.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feflood-001.html": [ + [ + "/css/filter-effects/tainting-feflood-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feflood-002.html": [ + [ + "/css/filter-effects/tainting-feflood-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feflood-dynamic.html": [ + [ + "/css/filter-effects/tainting-feflood-dynamic.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fegaussianblur-001.html": [ + [ + "/css/filter-effects/tainting-fegaussianblur-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fegaussianblur-002.html": [ + [ + "/css/filter-effects/tainting-fegaussianblur-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-femorphology-001.html": [ + [ + "/css/filter-effects/tainting-femorphology-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-femorphology-002.html": [ + [ + "/css/filter-effects/tainting-femorphology-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feoffset-001.html": [ + [ + "/css/filter-effects/tainting-feoffset-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-feoffset-002.html": [ + [ + "/css/filter-effects/tainting-feoffset-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fespecularlighting-001.html": [ + [ + "/css/filter-effects/tainting-fespecularlighting-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fespecularlighting-002.html": [ + [ + "/css/filter-effects/tainting-fespecularlighting-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fespecularlighting-003.html": [ + [ + "/css/filter-effects/tainting-fespecularlighting-003.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fetile-001.html": [ + [ + "/css/filter-effects/tainting-fetile-001.html", + [ + [ + "/css/filter-effects/reference/green-blue-stripe-100x100.html", + "==" + ] + ], + {} + ] + ], + "css/filter-effects/tainting-fetile-002.html": [ + [ + "/css/filter-effects/tainting-fetile-002.html", + [ + [ + "/css/filter-effects/reference/green-100x100.html", + "==" + ] + ], + {} + ] + ], "css/mediaqueries/aspect-ratio-001.html": [ [ "/css/mediaqueries/aspect-ratio-001.html", @@ -107955,6 +108351,30 @@ {} ] ], + "infrastructure/reftest/reftest_fuzzy.html": [ + [ + "/infrastructure/reftest/reftest_fuzzy.html", + [ + [ + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ] + ], + {} + ] + ], + "infrastructure/reftest/reftest_fuzzy_1.html": [ + [ + "/infrastructure/reftest/reftest_fuzzy_1.html", + [ + [ + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ] + ], + {} + ] + ], "infrastructure/reftest/reftest_match.html": [ [ "/infrastructure/reftest/reftest_match.html", @@ -108775,18 +109195,6 @@ {} ] ], - "shadow-dom/untriaged/shadow-trees/text-decoration-001.html": [ - [ - "/shadow-dom/untriaged/shadow-trees/text-decoration-001.html", - [ - [ - "/shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html", - "==" - ] - ], - {} - ] - ], "shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html": [ [ "/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html", @@ -142863,6 +143271,11 @@ {} ] ], + "css/css-sizing/range-percent-intrinsic-size-2a-ref.html": [ + [ + {} + ] + ], "css/css-sizing/support/dynamic-available-size-iframe.html": [ [ {} @@ -143498,6 +143911,11 @@ {} ] ], + "css/css-text-decor/reference/text-decoration-underline-ref.html": [ + [ + {} + ] + ], "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [ [ {} @@ -153948,6 +154366,11 @@ {} ] ], + "css/filter-effects/reference/green-blue-stripe-100x100.html": [ + [ + {} + ] + ], "css/filter-effects/reference/svg-feflood-ref.html": [ [ {} @@ -162088,6 +162511,11 @@ {} ] ], + "fetch/stale-while-revalidate/sw-intercept.js": [ + [ + {} + ] + ], "fonts/AD.woff": [ [ {} @@ -164663,6 +165091,11 @@ {} ] ], + "html/browsers/the-window-object/support/closed.html": [ + [ + {} + ] + ], "html/browsers/the-window-object/support/noopener-target.html": [ [ {} @@ -175213,6 +175646,11 @@ {} ] ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini": [ + [ + {} + ] + ], "infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini": [ [ {} @@ -175298,6 +175736,11 @@ {} ] ], + "infrastructure/reftest/fuzzy-ref-1.html": [ + [ + {} + ] + ], "infrastructure/reftest/green.html": [ [ {} @@ -184863,6 +185306,11 @@ {} ] ], + "service-workers/cache-storage/serviceworker/cache-match.https-expected.txt": [ + [ + {} + ] + ], "service-workers/cache-storage/serviceworker/cache-matchAll.https-expected.txt": [ [ {} @@ -184878,6 +185326,11 @@ {} ] ], + "service-workers/cache-storage/window/cache-match.https-expected.txt": [ + [ + {} + ] + ], "service-workers/cache-storage/window/cache-matchAll.https-expected.txt": [ [ {} @@ -184898,6 +185351,11 @@ {} ] ], + "service-workers/cache-storage/worker/cache-match.https-expected.txt": [ + [ + {} + ] + ], "service-workers/cache-storage/worker/cache-matchAll.https-expected.txt": [ [ {} @@ -186873,11 +187331,6 @@ {} ] ], - "shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html": [ - [ - {} - ] - ], "shadow-dom/untriaged/styles/not-apply-in-shadow-root-001-ref.html": [ [ {} @@ -244957,6 +245410,12 @@ {} ] ], + "fetch/stale-while-revalidate/fetch-sw.https.tentative.html": [ + [ + "/fetch/stale-while-revalidate/fetch-sw.https.tentative.html", + {} + ] + ], "fetch/stale-while-revalidate/fetch.tentative.html": [ [ "/fetch/stale-while-revalidate/fetch.tentative.html", @@ -246917,6 +247376,12 @@ } ] ], + "html/browsers/the-window-object/closed-attribute.window.js": [ + [ + "/html/browsers/the-window-object/closed-attribute.window.html", + {} + ] + ], "html/browsers/the-window-object/focus.window.js": [ [ "/html/browsers/the-window-object/focus.window.html", @@ -317789,7 +318254,7 @@ "testharness" ], "animation-worklet/playback-rate.https.html": [ - "dba27afe20e1087328339b03f917855af31d518c", + "5367497b831d87741bb4aca67d4e0efcee6389e2", "testharness" ], "animation-worklet/references/translated-box-ref.html": [ @@ -368069,11 +368534,11 @@ "testharness" ], "css/css-sizing/range-percent-intrinsic-size-1-ref.html": [ - "a4419eab319e0732ae9d2ca1422a8154fdf2a781", + "9a68590b6389eb9c1fefc2dc37f42b2a60b3b41a", "support" ], "css/css-sizing/range-percent-intrinsic-size-1.html": [ - "87399578988a1c09c5d031c9090cdce7ba34c783", + "018129aae3a7fcdc127c757d9b4ddba558115d3c", "reftest" ], "css/css-sizing/range-percent-intrinsic-size-2-ref.html": [ @@ -368084,6 +368549,14 @@ "e11e2955891f251409e8519abd48f10fb2dd89e9", "reftest" ], + "css/css-sizing/range-percent-intrinsic-size-2a-ref.html": [ + "815b0a1021cb9113c39fad85b5052429dc74533f", + "support" + ], + "css/css-sizing/range-percent-intrinsic-size-2a.html": [ + "f2c2431978b1596078f48727da0953f23e1f0d3e", + "reftest" + ], "css/css-sizing/support/dynamic-available-size-iframe.html": [ "8b61c876389e1fbd0792dd58763e3e2a3d4ef133", "support" @@ -369284,6 +369757,10 @@ "8c0bee6720355c6216ce6f11d27e2f1fb4d4b401", "support" ], + "css/css-text-decor/reference/text-decoration-underline-ref.html": [ + "2370054a8fbd5cb8c00bfb95401129d01de38d00", + "support" + ], "css/css-text-decor/reference/text-emphasis-color-001-ref.xht": [ "8380c197b326fa184369094e75c7748fff209ee2", "support" @@ -369408,6 +369885,10 @@ "ea6a0c86c19bb3bb27b04cc0c49d2bdf433c5dbf", "reftest" ], + "css/css-text-decor/text-decoration-propagation-shadow.html": [ + "ac365ee046666c7e2945d1e76622b38f723cf6a4", + "reftest" + ], "css/css-text-decor/text-decoration-serialization.tentative-expected.txt": [ "2fac902c4641be1db62dc791301731042c21d1c6", "support" @@ -394172,6 +394653,10 @@ "f718ea6abfbab54333ba674ff0dcd320d8672bcd", "support" ], + "css/filter-effects/reference/green-blue-stripe-100x100.html": [ + "01546f115d112aa27495b3fd45347b22e30fe7ee", + "support" + ], "css/filter-effects/reference/svg-feflood-ref.html": [ "5623b08ecd71b292e698ee249a79b59d0046300f", "support" @@ -394400,6 +394885,130 @@ "8c9e3ea05805a5030b8034a7a01e53d4984a39dc", "testharness" ], + "css/filter-effects/tainting-feblend-001.html": [ + "416f57849a479e01e2f70a489b92fc4f8bf0ecff", + "reftest" + ], + "css/filter-effects/tainting-feblend-002.html": [ + "3d753413a6cdf44d39d832f3171a8aceb0f6fb6b", + "reftest" + ], + "css/filter-effects/tainting-fecomponenttransfer-001.html": [ + "89c60ba9688b6d680dfa77924531f1ab738e6f65", + "reftest" + ], + "css/filter-effects/tainting-fecomponenttransfer-002.html": [ + "6f29b35ba3144fda4a6fbdce9dee5eaadfca83b5", + "reftest" + ], + "css/filter-effects/tainting-fecomposite-001.html": [ + "ddaa53e1e24c02bba47919dadd572bcb1e146173", + "reftest" + ], + "css/filter-effects/tainting-fecomposite-002.html": [ + "1e68378ac6cc2d6bd5444ea48c12768437ceea1c", + "reftest" + ], + "css/filter-effects/tainting-feconvolvematrix-001.html": [ + "eda1d7e2fc80346191af68a8b780ada1a70dea99", + "reftest" + ], + "css/filter-effects/tainting-feconvolvematrix-002.html": [ + "e7ec038fbdd249541af70caa704997f0c8c765f5", + "reftest" + ], + "css/filter-effects/tainting-fediffuselighting-001.html": [ + "bce3a291819a7273ae1926bfe8dd08314ece3a79", + "reftest" + ], + "css/filter-effects/tainting-fediffuselighting-002.html": [ + "773c25bf029940c84f2f9f8d50445a079755a34e", + "reftest" + ], + "css/filter-effects/tainting-fediffuselighting-003.html": [ + "0b7bb4d19af286e29cf7a64c5cc9c5ea89f5c908", + "reftest" + ], + "css/filter-effects/tainting-fediffuselighting-dynamic.html": [ + "89674095a0cab68653690b543b70c3385c69d0fe", + "reftest" + ], + "css/filter-effects/tainting-fedisplacementmap-001.html": [ + "2c99cc4981e71434bef0786e540945d20fec243a", + "reftest" + ], + "css/filter-effects/tainting-fedisplacementmap-002.html": [ + "9648b54bf3dfd90c40a7142f2ce5f4fc04e74608", + "reftest" + ], + "css/filter-effects/tainting-fedropshadow-001.html": [ + "1b3dbb497ce6a1dde712941ed2d0ca0628a55578", + "reftest" + ], + "css/filter-effects/tainting-fedropshadow-002.html": [ + "26fc687d88a08557c279f71db254e3f1acd55c36", + "reftest" + ], + "css/filter-effects/tainting-fedropshadow-003.html": [ + "d42102aa6c58204da2ed37352851428310403206", + "reftest" + ], + "css/filter-effects/tainting-feflood-001.html": [ + "714e6b992fbd91816366246b3970d4b612f0b339", + "reftest" + ], + "css/filter-effects/tainting-feflood-002.html": [ + "79ea8dac522df16c3532f620e68b6db8b5216b23", + "reftest" + ], + "css/filter-effects/tainting-feflood-dynamic.html": [ + "fc9b3354fab77cdcccb10a42e9dac73a35236587", + "reftest" + ], + "css/filter-effects/tainting-fegaussianblur-001.html": [ + "a938c7494fec6fd7024109338b8a31f6cf13dea1", + "reftest" + ], + "css/filter-effects/tainting-fegaussianblur-002.html": [ + "55dabbbdbb34d8f23f78c776f2080f6dd4656a58", + "reftest" + ], + "css/filter-effects/tainting-femorphology-001.html": [ + "9af566410d2f1aad93efea604280ef4ff680f708", + "reftest" + ], + "css/filter-effects/tainting-femorphology-002.html": [ + "2c097202ee888444a0b7dcf37564744dcd986771", + "reftest" + ], + "css/filter-effects/tainting-feoffset-001.html": [ + "8704b693e812388c44eff46a812718fc504dc1ba", + "reftest" + ], + "css/filter-effects/tainting-feoffset-002.html": [ + "3c04268f5cbedb46a26381ac8f5cdf9e4577e785", + "reftest" + ], + "css/filter-effects/tainting-fespecularlighting-001.html": [ + "c2825258a571c975f0cb6ea64966c2417f763fa7", + "reftest" + ], + "css/filter-effects/tainting-fespecularlighting-002.html": [ + "773b0c7065caffe13462982d7e30dc38c7706ec1", + "reftest" + ], + "css/filter-effects/tainting-fespecularlighting-003.html": [ + "173ed2da9f5ad935ea56ee8649c3a8a87c21eb46", + "reftest" + ], + "css/filter-effects/tainting-fetile-001.html": [ + "c5b955eef85246434a9e884d41e3b0c143608708", + "reftest" + ], + "css/filter-effects/tainting-fetile-002.html": [ + "ed77301d2ef6675662a5f3b121e2489e699cec10", + "reftest" + ], "css/geometry/DOMMatrix-001.html": [ "a8a357bff606925aaa95dce6c4642b81bd8c88ea", "testharness" @@ -410056,12 +410665,16 @@ "20d307e9188405dcec011042487aa2c7354930bf", "support" ], + "fetch/stale-while-revalidate/fetch-sw.https.tentative.html": [ + "2286739ecf27966d1efedad7c4d4031475693988", + "testharness" + ], "fetch/stale-while-revalidate/fetch.tentative.html": [ - "5b9b2dc5de2835d1f4a9f49cc63e0b3f03317698", + "33d844fd08f3352bff1677cabf0c1dd06177e40a", "testharness" ], "fetch/stale-while-revalidate/stale-css.py": [ - "425c889ac5ec58527e63ab25a4f70558b7daeef3", + "9566833e507603a35aadd4de622f388d4f77307f", "support" ], "fetch/stale-while-revalidate/stale-css.tentative.html": [ @@ -410069,7 +410682,7 @@ "testharness" ], "fetch/stale-while-revalidate/stale-image.py": [ - "ce7f0fc782613e0a36e3d0aba0521e45f1ca6bf0", + "e0cf94bcd0abc3e2f3aba3ad4448d5f519312335", "support" ], "fetch/stale-while-revalidate/stale-image.tentative.html": [ @@ -410077,13 +410690,17 @@ "testharness" ], "fetch/stale-while-revalidate/stale-script.py": [ - "0f91a9b83486678eabd600ecb6336695e5dd6970", + "5ea5987db3dd707b7ab77d11d883c0217705aaf6", "support" ], "fetch/stale-while-revalidate/stale-script.tentative.html": [ "8cbb54b7dab3bc9b9e8763c5358a9232d24c1e7f", "testharness" ], + "fetch/stale-while-revalidate/sw-intercept.js": [ + "dca7de51b0b8c5518276e70ae219b7bc8f869a95", + "support" + ], "fonts/AD.woff": [ "3df8ea8efdabd11bc45fdcc6d4f3fec771be6650", "support" @@ -413656,6 +414273,10 @@ "a9d42e26dea16afa9743d31aa7b72f3f09e46e68", "support" ], + "html/browsers/the-window-object/closed-attribute.window.js": [ + "88a3beba6f10b80b0b90acdc0b0f957e1a17cefc", + "testharness" + ], "html/browsers/the-window-object/focus.window.js": [ "6ec7feee281e756ae6452e0f9b17d9b93032d010", "testharness" @@ -413756,6 +414377,10 @@ "1fb0ed7c1e62da55b890c6434bee6e46637e0209", "testharness" ], + "html/browsers/the-window-object/support/closed.html": [ + "3b70598e34d0e9b46a8ba2150a1589fecfb90ea8", + "support" + ], "html/browsers/the-window-object/support/noopener-target.html": [ "41e197a74630ac70cb34ab2bf164b188767f7218", "support" @@ -414097,7 +414722,7 @@ "support" ], "html/browsers/windows/embedded-opener-remove-frame-expected.txt": [ - "b2fe3032be484df54f4e71aab73f3b0a36331caf", + "1d304732ae89dc1d919737f00e0d29eaec6d5e91", "support" ], "html/browsers/windows/embedded-opener-remove-frame.html": [ @@ -431121,7 +431746,7 @@ "testharness" ], "import-maps/resolving.tentative-expected.txt": [ - "4dc845e52ab307d1207f56e990be52d726459d97", + "b5da00638a0048517bd8af6c5909be4e906ec4e2", "support" ], "import-maps/resolving.tentative.html": [ @@ -431141,7 +431766,7 @@ "support" ], "import-maps/resources/resolving.js": [ - "ec2645e599119ab64949c016076164b40277006c", + "0409962e4d7904bd9ddbe8601b7328d8d0ad6d11", "support" ], "import-maps/resources/test-helper.js": [ @@ -431308,6 +431933,10 @@ "472b33f7764bde6e2aea7bc2ccd8bf3739babad2", "support" ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini": [ + "1ab2d770afef92b0af4eaf9153ce5344bbbdc964", + "support" + ], "infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini": [ "f3dc3362fac41bbe8ded44589e898ef589cb1a89", "support" @@ -431380,6 +432009,10 @@ "c2e9986ad85dde0483a553459964a0345399a782", "reftest" ], + "infrastructure/reftest/fuzzy-ref-1.html": [ + "e50fc11ef6ea80754e702becfbf675feebe3dbb9", + "support" + ], "infrastructure/reftest/green-ref.html": [ "0e145d60b55b3502639d15f10d4d63a6b0f79b7d", "reftest" @@ -431436,6 +432069,14 @@ "c8e548c462255638a32c474a177759ff6d7cceaf", "reftest_node" ], + "infrastructure/reftest/reftest_fuzzy.html": [ + "7429025798151b620dd72db71a46070aafe6c070", + "reftest" + ], + "infrastructure/reftest/reftest_fuzzy_1.html": [ + "1930fe0ae8fb1aee30e91e691fe6a73ccfc87d0e", + "reftest" + ], "infrastructure/reftest/reftest_match.html": [ "333cc6c1ecdf2000e4b118565661761b876a7299", "reftest" @@ -457565,7 +458206,7 @@ "support" ], "service-workers/cache-storage/script-tests/cache-match.js": [ - "b2b731cc6546529770c20a0bb5a30168d60b0ec6", + "8bf7fda30967fbb4ed25325d49e0cd99fc16df55", "support" ], "service-workers/cache-storage/script-tests/cache-matchAll.js": [ @@ -457616,6 +458257,10 @@ "736f74d98960aa81e1569432683705ccc7c3ceee", "testharness" ], + "service-workers/cache-storage/serviceworker/cache-match.https-expected.txt": [ + "3f30ee17d732d3526b7af3db038eebcc39d8c07c", + "support" + ], "service-workers/cache-storage/serviceworker/cache-match.https.html": [ "81db70943f0a9871719b704d094bfd042152f809", "testharness" @@ -457672,6 +458317,10 @@ "8398c33e146c5983c10922457b7f8591b49f5ed8", "testharness" ], + "service-workers/cache-storage/window/cache-match.https-expected.txt": [ + "7326e233734b782029455fa300496f7047a70c45", + "support" + ], "service-workers/cache-storage/window/cache-match.https.html": [ "f28efad0b76b341171ad230e18d243e229153687", "testharness" @@ -457732,6 +458381,10 @@ "6bafe21d30bb55d4e0dfdc8f3633bcf359fc7d6c", "testharness" ], + "service-workers/cache-storage/worker/cache-match.https-expected.txt": [ + "7326e233734b782029455fa300496f7047a70c45", + "support" + ], "service-workers/cache-storage/worker/cache-match.https.html": [ "479a29d1eec5f49416a075aae9306bcd5b5cc3e6", "testharness" @@ -460684,14 +461337,6 @@ "24d5d016b91a50f1b794c62b81e6ace1d8dd04ba", "reftest" ], - "shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html": [ - "8c10d251557cfecbdd2bbb1228db284f0fd4b971", - "support" - ], - "shadow-dom/untriaged/shadow-trees/text-decoration-001.html": [ - "d8def126d64a6c0c9b50677fba0b38e486cef479", - "reftest" - ], "shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html": [ "71421481e0739e566ea71e1cf59ba8457ce90197", "testharness" @@ -464053,7 +464698,7 @@ "support" ], "tools/manifest/item.py": [ - "c06daee3e24f07fbe83ab82c916e175832f386ed", + "c6363a707013e83e6ece724eee8069078a3413f4", "support" ], "tools/manifest/log.py": [ @@ -464065,7 +464710,7 @@ "support" ], "tools/manifest/sourcefile.py": [ - "b5d7cdf8799c98d5b7e00452a54fcd63ccd3e17b", + "78843b089b87c111efe24762e7bee55cf44f55ec", "support" ], "tools/manifest/update.py": [ @@ -468293,7 +468938,7 @@ "support" ], "tools/wptrunner/requirements.txt": [ - "24a7d3d7e0341472dd032c71d7abfd1f10425ca8", + "37f4fde47869bd0c1f30ab12ef96cb5d625b8c9d", "support" ], "tools/wptrunner/requirements_chrome.txt": [ @@ -468425,7 +469070,7 @@ "support" ], "tools/wptrunner/wptrunner/environment.py": [ - "493d3c43fc06ff1e0bc2105a2c86fb851b3f4de9", + "6563721caee8288047ac84ef62456ce0723738bc", "support" ], "tools/wptrunner/wptrunner/executors/__init__.py": [ @@ -468433,7 +469078,7 @@ "support" ], "tools/wptrunner/wptrunner/executors/base.py": [ - "8958ecfc3bb240ebda2999098f04951d14c90b6e", + "5fa30563890cc1d95bc7cd1843c0aeca4dd3e197", "support" ], "tools/wptrunner/wptrunner/executors/executorchrome.py": [ @@ -468449,7 +469094,7 @@ "support" ], "tools/wptrunner/wptrunner/executors/executormarionette.py": [ - "b70f0ed0b0c2dc9d7dd0fe24934818c0a25f2d3b", + "f9fd97b6ba8b88907db2115157407d153b443a82", "support" ], "tools/wptrunner/wptrunner/executors/executoropera.py": [ @@ -468473,7 +469118,7 @@ "support" ], "tools/wptrunner/wptrunner/executors/executorwebdriver.py": [ - "73f5fcf84a8e742ea74a4d96760547671d593252", + "563252ce2bbfee5a3a92fd39d8c171d8aacdeb18", "support" ], "tools/wptrunner/wptrunner/executors/executorwebkit.py": [ @@ -468541,7 +469186,7 @@ "support" ], "tools/wptrunner/wptrunner/manifestexpected.py": [ - "80284bd8a215e73a1140239a9aec1f312d8cacb5", + "fb3ef627d94dc643f2e64fb0c7203621214e4267", "support" ], "tools/wptrunner/wptrunner/manifestinclude.py": [ @@ -468645,7 +469290,7 @@ "support" ], "tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py": [ - "4eb292efb7508a0aac72f392c1af0e88e07fe5fc", + "7ad35756d0c6c34282f3d1a278a40b98a882ae9d", "support" ], "tools/wptrunner/wptrunner/wptmanifest/backends/static.py": [ @@ -468693,7 +469338,7 @@ "support" ], "tools/wptrunner/wptrunner/wpttest.py": [ - "dc1c6b63aefef5ab225bef70e6c3f09e379f60e2", + "6a4fa4fdf82dca14e44d8e3c6d63ce2c7e2b56b2", "support" ], "tools/wptserve/LICENSE": [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-key.html b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-key.html deleted file mode 100644 index 2fbe95e..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-key.html +++ /dev/null
@@ -1,82 +0,0 @@ -<!doctype html> -<meta charset=utf-8> -<title>IndexedDB: ES bindings - Inject a key into a value</title> -<meta name="help" href="https://w3c.github.io/IndexedDB/#inject-key-into-value"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="support-promises.js"></script> -<script> - -promise_test(async t => { - const db = await createDatabase(t, db => { - db.createObjectStore('store'); - }); - - let setter_called = false; - Object.defineProperty(Object.prototype, '10', { - configurable: true, - set: value => { setter_called = true; }, - }); - t.add_cleanup(() => { delete Object.prototype['10']; }); - - const tx = db.transaction('store', 'readwrite'); - const result = await promiseForRequest(t, tx.objectStore('store').put( - 'value', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'key'])); - - assert_false(setter_called, - 'Setter should not be called for key result.'); - assert_true(result.hasOwnProperty('10'), - 'Result should have own-property overriding prototype setter.'); - assert_equals(result[10], 'key', - 'Result should have expected property.'); -}, 'Returning keys to script should bypass prototype setters'); - -promise_test(async t => { - const db = await createDatabase(t, db => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); - }); - - let setter_called = false; - Object.defineProperty(Object.prototype, 'id', { - configurable: true, - set: value => { setter_called = true; }, - }); - t.add_cleanup(() => { delete Object.prototype['id']; }); - - const tx = db.transaction('store', 'readwrite'); - tx.objectStore('store').put({}); - const result = await promiseForRequest(t, tx.objectStore('store').get(1)); - - assert_false(setter_called, - 'Setter should not be called for key result.'); - assert_true(result.hasOwnProperty('id'), - 'Result should have own-property overriding prototype setter.'); - assert_equals(result.id, 1, - 'Own property should match primary key generator value'); -}, 'Returning values to script should bypass prototype setters'); - -promise_test(async t => { - const db = await createDatabase(t, db => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.c'}); - }); - - Object.prototype.a = {b: {c: 'on proto'}}; - t.add_cleanup(() => { delete Object.prototype.a; }); - - const tx = db.transaction('store', 'readwrite'); - tx.objectStore('store').put({}); - const result = await promiseForRequest(t, tx.objectStore('store').get(1)); - - assert_true(result.hasOwnProperty('a'), - 'Result should have own-properties overriding prototype.'); - assert_true(result.a.hasOwnProperty('b'), - 'Result should have own-properties overriding prototype.'); - assert_true(result.a.b.hasOwnProperty('c'), - 'Result should have own-properties overriding prototype.'); - assert_equals(result.a.b.c, 1, - 'Own property should match primary key generator value'); - assert_equals(Object.prototype.a.b.c, 'on proto', - 'Prototype should not be modified'); -}, 'Returning values to script should bypass prototype chain'); - -</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-keys-bypass-setters.html b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-keys-bypass-setters.html new file mode 100644 index 0000000..91d586b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-keys-bypass-setters.html
@@ -0,0 +1,35 @@ +<!doctype html> +<meta charset=utf-8> +<title>IndexedDB: ES bindings - Inject a key into a value - Keys bypass setters</title> +<meta name="help" +href="https://w3c.github.io/IndexedDB/#inject-key-into-value-keys-bypass-setters"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support-promises.js"></script> +<script> + +promise_test(async t => { + const db = await createDatabase(t, db => { + db.createObjectStore('store'); + }); + + let setter_called = false; + Object.defineProperty(Object.prototype, '10', { + configurable: true, + set: value => { setter_called = true; }, + }); + t.add_cleanup(() => { delete Object.prototype['10']; }); + + const tx = db.transaction('store', 'readwrite'); + const result = await promiseForRequest(t, tx.objectStore('store').put( + 'value', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'key'])); + + assert_false(setter_called, + 'Setter should not be called for key result.'); + assert_true(result.hasOwnProperty('10'), + 'Result should have own-property overriding prototype setter.'); + assert_equals(result[10], 'key', + 'Result should have expected property.'); +}, 'Returning keys to script should bypass prototype setters'); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-chain.html b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-chain.html new file mode 100644 index 0000000..02fdb8a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-chain.html
@@ -0,0 +1,35 @@ +<!doctype html> +<meta charset=utf-8> +<title>IndexedDB: ES bindings - Inject a key into a value - Values bypass chain</title> +<meta name="help" +href="https://w3c.github.io/IndexedDB/#inject-key-into-value-values-bypass-chain"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support-promises.js"></script> +<script> + +promise_test(async t => { + const db = await createDatabase(t, db => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.c'}); + }); + + Object.prototype.a = {b: {c: 'on proto'}}; + t.add_cleanup(() => { delete Object.prototype.a; }); + + const tx = db.transaction('store', 'readwrite'); + tx.objectStore('store').put({}); + const result = await promiseForRequest(t, tx.objectStore('store').get(1)); + + assert_true(result.hasOwnProperty('a'), + 'Result should have own-properties overriding prototype.'); + assert_true(result.a.hasOwnProperty('b'), + 'Result should have own-properties overriding prototype.'); + assert_true(result.a.b.hasOwnProperty('c'), + 'Result should have own-properties overriding prototype.'); + assert_equals(result.a.b.c, 1, + 'Own property should match primary key generator value'); + assert_equals(Object.prototype.a.b.c, 'on proto', + 'Prototype should not be modified'); +}, 'Returning values to script should bypass prototype chain'); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-setters.html b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-setters.html new file mode 100644 index 0000000..c16c0a4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/bindings-inject-values-bypass-setters.html
@@ -0,0 +1,36 @@ +<!doctype html> +<meta charset=utf-8> +<title>IndexedDB: ES bindings - Inject a key into a value - Values bypass + setters</title> +<meta name="help" +href="https://w3c.github.io/IndexedDB/#inject-key-into-value-values-bypass-setters"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support-promises.js"></script> +<script> + +promise_test(async t => { + const db = await createDatabase(t, db => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); + }); + + let setter_called = false; + Object.defineProperty(Object.prototype, 'id', { + configurable: true, + set: value => { setter_called = true; }, + }); + t.add_cleanup(() => { delete Object.prototype['id']; }); + + const tx = db.transaction('store', 'readwrite'); + tx.objectStore('store').put({}); + const result = await promiseForRequest(t, tx.objectStore('store').get(1)); + + assert_false(setter_called, + 'Setter should not be called for key result.'); + assert_true(result.hasOwnProperty('id'), + 'Result should have own-property overriding prototype setter.'); + assert_equals(result.id, 1, + 'Own property should match primary key generator value'); +}, 'Returning values to script should bypass prototype setters'); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/playback-rate.https.html b/third_party/blink/web_tests/external/wpt/animation-worklet/playback-rate.https.html index dba27af..5367497 100644 --- a/third_party/blink/web_tests/external/wpt/animation-worklet/playback-rate.https.html +++ b/third_party/blink/web_tests/external/wpt/animation-worklet/playback-rate.https.html
@@ -87,11 +87,11 @@ animation.play(); - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); // Make sure the current time is not Zero. - await waitForNextFrame(); + await waitForDocumentTimelineAdvance(); // Set playback rate while the animation is playing. const prevCurrentTime = animation.currentTime; @@ -104,11 +104,11 @@ promise_test(async t => { const animation = createWorkletAnimation(t); - const playbackRate = 2; + const playbackRate = 0.2; animation.play(); - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); @@ -118,7 +118,7 @@ animation.playbackRate = playbackRate; // Play the animation some more. - await waitForNextFrame(); + await waitForDocumentTimelineAdvance(); const currentTime = animation.currentTime; const currentTimelineTime = document.timeline.currentTime; @@ -126,7 +126,7 @@ assert_times_equal( currentTime - prevCurrentTime, (currentTimelineTime - prevTimelineTime) * playbackRate, - 'The current time should increase two times faster than timeline.'); + 'The current time should increase 0.2 times faster than timeline.'); }, 'The playback rate affects the rate of progress of the current time.'); promise_test(async t => { @@ -135,13 +135,13 @@ // Set playback rate while the animation is in 'idle' state. animation.playbackRate = playbackRate; + const prevTimelineTime = document.timeline.currentTime; animation.play(); - waitForAnimationFrameWithCondition(_=> { + + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); - const prevTimelineTime = document.timeline.currentTime; - - await waitForNextFrame(); + await waitForDocumentTimelineAdvance(); const currentTime = animation.currentTime; const timelineTime = document.timeline.currentTime; @@ -158,28 +158,48 @@ fill: 'none', iterations: 1 }; + // TODO(crbug.com/937382): Currently composited + // workletAnimation.currentTime and the corresponding + // effect.getComputedTiming().localTime are computed by main and + // compositing threads respectively and, as a result, don't match. + // To workaround this limitation we compare the output of two identical + // animations that only differ in playback rate. The expectation is that + // their output matches after taking their playback rates into + // consideration. This works since these two animations start at the same + // time on the same thread. + // Once the issue is fixed, this test needs to change so expected + // effect.getComputedTiming().localTime is compared against + // workletAnimation.currentTime. const target = createDiv(t); + const targetRef = createDiv(t); const keyframeEffect = new KeyframeEffect( - target, { opacity: [0, 1] }, timing); + target, { opacity: [1, 0] }, timing); + const keyframeEffectRef = new KeyframeEffect( + targetRef, { opacity: [1, 0] }, timing); const animation = new WorkletAnimation( 'passthrough', keyframeEffect, document.timeline); + const animationRef = new WorkletAnimation( + 'passthrough', keyframeEffectRef, document.timeline); const playbackRate = 2; - - animation.play(); - waitForAnimationFrameWithCondition(_=> { - return animation.playState == "running" - }); animation.playbackRate = playbackRate; + animation.play(); + animationRef.play(); - await waitForNextFrame(); + // wait until local times are synced back to the main thread. + await waitForAnimationFrameWithCondition(_ => { + return getComputedStyle(target).opacity != '1'; + }); assert_times_equal( - keyframeEffect.getComputedTiming().localTime, animation.currentTime, + keyframeEffect.getComputedTiming().localTime, + keyframeEffectRef.getComputedTiming().localTime * playbackRate, 'When playback rate is set on WorkletAnimation, the underlying ' + 'effect\'s timing should be properly updated.'); - assert_approx_equals(Number(getComputedStyle(target).opacity), - animation.currentTime / 100, 0.001, + assert_approx_equals( + 1 - Number(getComputedStyle(target).opacity), + (1 - Number(getComputedStyle(targetRef).opacity)) * playbackRate, + 0.001, 'When playback rate is set on WorkletAnimation, the underlying effect' + ' should produce correct visual result.'); }, 'When playback rate is updated, the underlying effect is properly ' + @@ -195,7 +215,7 @@ animation.playbackRate = 0.5; animation.play(); - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); assert_equals(animation.currentTime, 0.2 * timeRange * 0.5, @@ -212,9 +232,7 @@ animation.play(); animation.playbackRate = 0.5; - waitForAnimationFrameWithCondition(_=> { - return animation.playState == "running" - }); + assert_equals(animation.currentTime, 0.2 * timeRange, 'Initial current time is not affected by playbackRate.'); }, 'Initial current time is not affected by playbackRate set while '+ @@ -229,7 +247,7 @@ animation.play(); scroller.scrollTop = 0.2 * maxScroll; - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); // Set playback rate while the animation is playing. @@ -247,7 +265,7 @@ const timeRange = animation.timeline.timeRange; animation.play(); - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); scroller.scrollTop = 0.1 * maxScroll; @@ -273,7 +291,7 @@ // Set playback rate while the animation is in 'idle' state. animation.playbackRate = playbackRate; animation.play(); - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); scroller.scrollTop = 0.2 * maxScroll; @@ -296,7 +314,7 @@ }; const target = createDiv(t); const keyframeEffect = new KeyframeEffect( - target, { opacity: [0, 1] }, timing); + target, { opacity: [1, 0] }, timing); const animation = new WorkletAnimation( 'passthrough', keyframeEffect, timeline); const playbackRate = 2; @@ -305,12 +323,15 @@ animation.play(); animation.playbackRate = playbackRate; - waitForAnimationFrameWithCondition(_=> { + await waitForAnimationFrameWithCondition(_=> { return animation.playState == "running" }); scroller.scrollTop = 0.2 * maxScroll; - await waitForNextFrame(); + // wait until local times are synced back to the main thread. + await waitForAnimationFrameWithCondition(_ => { + return getComputedStyle(target).opacity != '1'; + }); assert_times_equal( keyframeEffect.getComputedTiming().localTime, @@ -319,7 +340,7 @@ 'effect\'s timing should be properly updated.'); assert_approx_equals( Number(getComputedStyle(target).opacity), - 0.2 * timeRange * playbackRate / 1000, 0.001, + 1 - 0.2 * timeRange * playbackRate / 1000, 0.001, 'When playback rate is set on WorkletAnimation, the underlying ' + 'effect should produce correct visual result.'); }, 'When playback rate is updated, the underlying effect is properly ' +
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html index 9841c575..6f98185 100644 --- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html +++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html
@@ -61,7 +61,10 @@ const animation = new WorkletAnimation('passthrough', effect, timeline); animation.play(); + // Ensure that the WorkletAnimation will have been started on the compositor. waitForAsyncAnimationFrames(1).then(_ => { + // Now return the scroller to the world, which will cause it to be composited + // and the animation should update on the compositor side. scroller.classList.remove('removed'); const maxScroll = scroller.scrollHeight - scroller.clientHeight; scroller.scrollTop = 0.5 * maxScroll;
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-overflow-hidden-ref.html b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-overflow-hidden-ref.html index 2004e6df..c6d7314e 100644 --- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-overflow-hidden-ref.html +++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-and-overflow-hidden-ref.html
@@ -7,6 +7,7 @@ background-color: green; transform: translate(0, 100px); opacity: 0.5; + will-change: transform; /* force compositing */ } #covered { @@ -19,6 +20,7 @@ overflow: hidden; height: 100px; width: 100px; + will-change: transform; /* force compositing */ } #contents {
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-ref.html b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-ref.html index f30c861f..fe92232 100644 --- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-ref.html +++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-ref.html
@@ -7,6 +7,7 @@ background-color: green; transform: translate(0, 100px); opacity: 0.5; + will-change: transform; /* force compositing */ } #covered { @@ -19,8 +20,7 @@ overflow: auto; height: 100px; width: 100px; - /* TODO(yigu): Rewrite the test to not rely on compositing. */ - will-change: transform; + will-change: transform; /* force compositing */ } #contents {
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller-ref.html b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller-ref.html index 3b527dc..5810e17 100644 --- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller-ref.html +++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller-ref.html
@@ -14,6 +14,7 @@ background-color: green; transform: translate(0, 100px); opacity: 0.5; + will-change: transform; /* force compositing */ } #covered {
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-navigator-clipboard-basics.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-navigator-clipboard-basics.https.html index 3c1a0af7..2d2ebf6 100644 --- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-navigator-clipboard-basics.https.html +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-navigator-clipboard-basics.https.html
@@ -11,32 +11,25 @@ assert_equals(navigator.clipboard, navigator.clipboard); }, "navigator.clipboard exists"); -/* clipboard.write(text/plain Blob) */ - promise_test(async () => { const blob = new Blob(["hello"], {type: 'text/plain'}); - await navigator.clipboard.write(blob); -}, "navigator.clipboard.write(text/plain Blob) succeeds"); - -/* clipboard.write(invalid input) */ + await navigator.clipboard.write([blob]); +}, "navigator.clipboard.write([text/plain Blob]) succeeds"); promise_test(async t => { await promise_rejects(t, new TypeError(), navigator.clipboard.write()); -}, "navigator.clipboard.write() fails (expect Blob)"); +}, "navigator.clipboard.write() fails (expect [Blob])"); promise_test(async t => { await promise_rejects(t, new TypeError(), navigator.clipboard.write(null)); -}, "navigator.clipboard.write(null) fails (expect Blob)"); +}, "navigator.clipboard.write(null) fails (expect [Blob])"); promise_test(async t => { await promise_rejects(t, new TypeError(), navigator.clipboard.write("Bad string")); -}, "navigator.clipboard.write(DOMString) fails (expect Blob)"); - - -/* clipboard.writeText() */ +}, "navigator.clipboard.write(DOMString) fails (expect [Blob])"); promise_test(async () => { await navigator.clipboard.writeText("New clipboard text"); @@ -47,27 +40,21 @@ navigator.clipboard.writeText()); }, "navigator.clipboard.writeText() fails (expect DOMString)"); -/* clipboard.write(image/png Blob) */ - promise_test(async () => { const fetched = await fetch( 'http://localhost:8001/clipboard-apis/resources/greenbox.png'); const image = await fetched.blob(); - await navigator.clipboard.write(image); -}, "navigator.clipboard.write(image/png Blob) succeeds"); - -/* text/plain or image/png Blob clipboard.read() */ + await navigator.clipboard.write([image]); +}, "navigator.clipboard.write([image/png Blob]) succeeds"); promise_test(async () => { const result = await navigator.clipboard.read(); - assert_true(result instanceof Blob); + assert_true(result instanceof Array); + assert_true(result[0] instanceof Blob); assert_equals(typeof result, "object"); }, "navigator.clipboard.read() succeeds"); - -/* clipboard.readText() */ - promise_test(async () => { const result = await navigator.clipboard.readText(); assert_equals(typeof result, "string");
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobs-read-blobs-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobs-read-blobs-manual.https.html new file mode 100644 index 0000000..e616b5e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobs-read-blobs-manual.https.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Async Clipboard write blobs -> read blobs tests +</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +async function loadBlob(fileName) { + const fetched = await fetch(fileName); + return await fetched.blob(); +} + +promise_test(async t => { + const blobText = new Blob(["test text"], {type: 'text/plain'}); + const blobImage = await loadBlob('resources/greenbox.png'); + + assert_equals(blobText.type, "text/plain"); + assert_equals(blobImage.type, "image/png"); + + await navigator.clipboard.write([blobText, blobImage]); + const output = await navigator.clipboard.read(); + + assert_equals(output.length, 2); + assert_equals(output[0].type, "text/plain"); + assert_equals(output[1].type, "image/png"); +}, "Verify write and read clipboard (multiple blobs)"); +</script> +<p> + Note: This is a manual test because it writes/reads to the shared system + clipboard and thus cannot be run async with other tests that might interact + with the clipboard. +</p>
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html index ea6e936..bc8511e 100644 --- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html
@@ -1,6 +1,8 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard write (text/plain Blob) -> read (text/plain Blob) tests</title> +<title> + Async Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) tests +</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> @@ -8,8 +10,10 @@ promise_test(async t => { const blobInput = new Blob([textInput], {type: 'text/plain'}); - await navigator.clipboard.write(blobInput); - const blobOutput = await navigator.clipboard.read(); + await navigator.clipboard.write([blobInput]); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; assert_equals(blobOutput.type, "text/plain"); const textOutput = await (new Response(blobOutput)).text(); @@ -17,7 +21,7 @@ }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write (text/plain Blob) -> read (text/plain Blob) test"); +readWriteTest("Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) test"); readWriteTest("non-Latin1 text encoding test データ"); </script> <p>
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-text-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-text-manual.https.html index ecb744a..b1b85de6 100644 --- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-text-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-blobtext-read-text-manual.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard write (text/plain Blob) -> readText tests</title> +<title>Async Clipboard write ([text/plain Blob]) -> readText tests</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> @@ -8,14 +8,14 @@ promise_test(async t => { const blobInput = new Blob([textInput], {type: 'text/plain'}); - await navigator.clipboard.write(blobInput); + await navigator.clipboard.write([blobInput]); const textOutput = await navigator.clipboard.readText(); assert_equals(textOutput, textInput); }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write (text/plain Blob) -> read text test"); +readWriteTest("Clipboard write ([text/plain Blob]) -> read text test"); readWriteTest("non-Latin1 text encoding test データ"); </script> <p>
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-duplicate-mime-type-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-duplicate-mime-type-manual.https.html new file mode 100644 index 0000000..8e249fc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-duplicate-mime-type-manual.https.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Async Clipboard write duplicate mime type test +</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +promise_test(async t => { + const blobText = new Blob(["test text"], {type: 'text/plain'}); + const blobText2 = new Blob(["test text"], {type: 'text/plain'}); + + assert_equals(blobText.type, "text/plain"); + assert_equals(blobText2.type, "text/plain"); + + + await promise_rejects(t, 'NotAllowedError', + navigator.clipboard.write([blobText, blobText2])); +}, "Verify write and read clipboard (multiple blobs)"); +</script> +<p> + Note: This is a manual test because it writes/reads to the shared system + clipboard and thus cannot be run async with other tests that might interact + with the clipboard. +</p>
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-image-read-image-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-image-read-image-manual.https.html index a8e2956..76d3d872 100644 --- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-image-read-image-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-image-read-image-manual.https.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <meta charset="utf-8"> <title> - Async Clipboard write image/png Blob -> read image/png Blob tests + Async Clipboard write [image/png Blob] -> read [image/png Blob] tests </title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -37,21 +37,23 @@ } promise_test(async t => { - const input = await loadBlob('resources/greenbox.png'); + const blobInput = await loadBlob('resources/greenbox.png'); - assert_equals(input.type, "image/png"); - await navigator.clipboard.write(input); - const output = await navigator.clipboard.read(); - assert_equals(output.type, "image/png"); + assert_equals(blobInput.type, "image/png"); + await navigator.clipboard.write([blobInput]); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; + assert_equals(blobOutput.type, "image/png"); document.getElementById('image-on-clipboard').src = - window.URL.createObjectURL(output); + window.URL.createObjectURL(blobOutput); - const comparableInput = await getBitmapString(input); - const comparableOutput = await getBitmapString(output); + const comparableInput = await getBitmapString(blobInput); + const comparableOutput = await getBitmapString(blobOutput); assert_equals(comparableOutput, comparableInput); -}, "Verify write and read clipboard (DOMString)"); +}, "Verify write and read clipboard ([image/png Blob])"); </script> <p> Note: This is a manual test because it writes/reads to the shared system
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-text-read-blobtext-manual.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-text-read-blobtext-manual.https.html index 7e682f1d..b54fa60 100644 --- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-text-read-blobtext-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-write-text-read-blobtext-manual.https.html
@@ -1,13 +1,15 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>Async Clipboard writeText -> read (text/plain Blob) tests</title> +<title>Async Clipboard writeText -> read ([text/plain Blob]) tests</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> async function readWriteTest(textInput) { promise_test(async t => { await navigator.clipboard.writeText(textInput); - const blobOutput = await navigator.clipboard.read(); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; assert_equals(blobOutput.type, "text/plain"); const textOutput = await (new Response(blobOutput)).text(); @@ -15,7 +17,7 @@ }, "Verify write and read clipboard given text: " + textInput); } -readWriteTest("Clipboard write text -> read (text/plain Blob) test"); +readWriteTest("Clipboard write text -> read ([text/plain Blob]) test"); readWriteTest("non-Latin1 text encoding test データ"); </script> <p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1-ref.html index a4419ea..9a68590b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1-ref.html
@@ -69,10 +69,6 @@ <input type="range" class="i" style="max-width:50%"> </div></div> -<div class="grid" style="grid-template-columns:4px"> - <input type="range" class="i" style="width:2px;"> -</div> - <div class="grid" style="grid-template-columns:30px"> <input type="range" class="i" style="width:15px"> </div> @@ -89,10 +85,6 @@ <input type="range" class="i n" style="width:14px; margin-right:0"> </div></div> -<div class="grid" style="grid-template-columns:4px"> - <input type="range" class="i n" style="width:2px;"> -</div> - <div class="grid" style="grid-template-columns:30px"> <input type="range" class="i n" style="width:15px"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1.html index 87399578..018129aae 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1.html +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-1.html
@@ -77,10 +77,6 @@ <input type="range" class="i"> </div></div> -<div class="grid"> - <input type="range" class="i"> -</div> - <div class="grid" style="grid-template-columns:minmax(min-content,30px)"> <input type="range" class="i"> </div> @@ -97,10 +93,6 @@ <input type="range" class="i n"> </div></div> -<div class="grid"> - <input type="range" class="i n"> -</div> - <div class="grid" style="grid-template-columns:minmax(min-content,30px)"> <input type="range" class="i n"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html new file mode 100644 index 0000000..815b0a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html
@@ -0,0 +1,86 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html><head> + <meta charset="utf-8"> + <title>Reference: INPUT type=range percent intrinsic block-size</title> + <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1513959"> + <style> +html,body { + color:black; background-color:white; font:16px/1 monospace; +} + +input { margin: 2px; } + +input.b { + min-height: 0; + background: lime; +} + +input.mb { + min-height: 0; + max-height: 100%; + background: lime; +} + +div { + display: inline-block; + border:1px solid; +} + +.grid { + display: inline-grid; + grid: auto / min-content; + place-items: start; +} +input[orient="vertical"] { + -webkit-appearance: slider-vertical; + -webkit-appearance: range; +} + +</style></head><body> + +<div style="height:30px"><div> + <input type="range" class="b" orient="vertical"> +</div></div> + +<div class="grid" style="grid: min-content / auto"> + <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1"> + <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1"> +</div> + +<div class="grid" style="grid: min-content / auto"> + <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1"> + <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1"> +</div> + +<div class="grid" style="grid: 30px / auto"> + <input type="range" class="b" orient="vertical" style="height:15px"> +</div> + +<div class="grid" style="grid: 30px / auto"> + <input type="range" class="b" orient="vertical" style="height:15px"> +</div> + +<br> +<br> + +<div style="height:30px"><div> + <input type="range" class="mb" orient="vertical"> +</div></div> + +<div class="grid" style="grid: 30px / auto"> + <input type="range" class="b" orient="vertical" style="height:15px"> +</div> + +<div class="grid" style="grid: 30px / auto"> + <input type="range" class="b" orient="vertical" style="height:15px"> +</div> + +<div class="grid" style="grid: 30px / auto"> + <input type="range" class="b" orient="vertical" style="height:15px"> +</div> + +</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a.html new file mode 100644 index 0000000..f2c2431 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a.html
@@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html><head> + <meta charset="utf-8"> + <title>Test: INPUT type=range percent intrinsic block-size</title> + <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1513959"> + <link rel="help" href="https://drafts.csswg.org/css-sizing-3/#percentage-sizing"> + <link rel="help" href="https://drafts.csswg.org/css-sizing-3/#min-content-zero"> + <link rel="match" href="range-percent-intrinsic-size-2a-ref.html"> + <style> +html,body { + color:black; background-color:white; font:16px/1 monospace; +} + +input { margin: 2px; } + +input.b { + height: 50%; + min-height: -moz-min-content; + min-height: min-content; + background: lime; +} + +input.mb { + max-height: 50%; + min-height: -moz-min-content; + min-height: min-content; + background: lime; +} + +input.b.min-auto, input.mb.min-auto, { + min-height: auto; +} + +div { + display: inline-block; + border:1px solid; +} + +.grid { + display: inline-grid; + grid: auto / min-content; + place-items: start; +} +input[orient="vertical"] { + -webkit-appearance: slider-vertical; + -webkit-appearance: range; +} + +</style></head><body> + +<div style="height:30px"><div> + <input type="range" class="b" orient="vertical"> +</div></div> + +<div class="grid" style="grid: min-content / auto"> + <input type="range" class="b" orient="vertical"> +</div> + +<div class="grid" style="grid: minmax(min-content,30px) / auto"> + <input type="range" class="b" orient="vertical"> +</div> + +<div class="grid" style="grid: minmax(auto,30px) / auto"> + <input type="range" class="b" orient="vertical"> +</div> + +<div class="grid" style="grid: minmax(auto,30px) / auto"> + <input type="range" class="b min-auto" orient="vertical"> +</div> + +<br> +<br> + +<div style="height:30px"><div> + <input type="range" class="mb" orient="vertical"> +</div></div> + +<div class="grid" style="grid: minmax(min-content,30px) / auto"> + <input type="range" class="mb" orient="vertical"> +</div> + +<div class="grid" style="grid: minmax(auto,30px) / auto"> + <input type="range" class="mb" orient="vertical"> +</div> + +<div class="grid" style="grid: minmax(auto,30px) / auto"> + <input type="range" class="mb min-auto" orient="vertical"> +</div> + +</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/closed-attribute.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/closed-attribute.window.js new file mode 100644 index 0000000..88a3beb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/closed-attribute.window.js
@@ -0,0 +1,69 @@ +// META: script=/common/get-host-info.sub.js + +function closedTest(newWindow, closeNewWindowsBrowsingContext) { + assert_equals(newWindow.closed, false); + closeNewWindowsBrowsingContext(); + assert_equals(newWindow.closed, true); +} + +test(() => { + const frame = document.body.appendChild(document.createElement("iframe")); + closedTest(frame.contentWindow, () => frame.remove()); +}, "closed and same-origin nested browsing context"); + +test(() => { + const openee = window.open(); + closedTest(openee, () => openee.close()); + + // close() is a no-op once "is closing" is set + openee.close(); + assert_equals(openee.closed, true); +}, "closed/close() and same-origin auxiliary browsing context"); + +const support = new URL("support/closed.html", location.href).pathname; +[ + { + type: "cross-origin", + url: `${get_host_info().HTTP_REMOTE_ORIGIN}${support}` + }, + { + type: "cross-site", + url: `${get_host_info().HTTP_NOTSAMESITE_ORIGIN}${support}` + } +].forEach(val => { + async_test(t => { + const frame = document.createElement("iframe"), + ident = `${val.type}-nested-bc`; + frame.src = `${val.url}?window=parent&ident=${ident}`; + const listener = t.step_func(e => { + if (e.data === ident) { + closedTest(frame.contentWindow, () => frame.remove()); + self.removeEventListener("message", listener); + t.done(); + } + }); + // Use a message event rather than onload for consistency with auxiliary browsing contexts. + self.addEventListener("message", listener); + document.body.append(frame); + }, `closed and ${val.type} nested browsing context`); + + async_test(t => { + const ident = `${val.type}-auxiliary-bc`, + support = new URL("support/closed.html", location.href).pathname, + openee = window.open(`${val.url}?window=opener&ident=${ident}`), + listener = t.step_func(e => { + if (e.data === ident) { + closedTest(openee, () => openee.close()); + + // close() is a no-op once "is closing" is set + openee.close(); + assert_equals(openee.closed, true); + + self.removeEventListener("message", listener); + t.done(); + } + }); + // As there's no cross-origin onload, use a message event. + self.addEventListener("message", listener); + }, `closed/close() and ${val.type} auxiliary browsing context`); +});
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/closed.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/closed.html new file mode 100644 index 0000000..3b70598e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/closed.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<!-- + There's two URL parameters supported here: + + window: The property name of a getter on the global object that returns the relevant WindowProxy + object to message. + ident: A reasonably unique identifier that will be echoed as the message. +--> +<script> + const params = new URLSearchParams(location.search); + self[params.get("window")].postMessage(params.get("ident"), "*"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt index b2fe3032..1d304732 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. -FAIL opener and "removed" embedded documents openerGet is not a function +FAIL opener of discarded nested browsing context openerGet is not a function +FAIL opener of discarded auxiliary browsing context openerGet is not a function Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini new file mode 100644 index 0000000..1ab2d77 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini
@@ -0,0 +1,2 @@ +[reftest_fuzzy.html] + fuzzy: fuzzy-ref-1.html:maxDifference=255;100-100
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/fuzzy-ref-1.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/fuzzy-ref-1.html new file mode 100644 index 0000000..e50fc11 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/fuzzy-ref-1.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +</style> +<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html new file mode 100644 index 0000000..7429025 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel=match href=fuzzy-ref-1.html> +<!-- This meta is overridden in the corresponding ini file --> +<meta name=fuzzy content="fuzzy-ref-1.html:128;100"> +<style> +div { + width: 99px; + height: 100px; + background-color: green; +} +</style> +<div></div> +
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_1.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_1.html new file mode 100644 index 0000000..1930fe0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_1.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel=match href=fuzzy-ref-1.html> +<meta name=fuzzy content="fuzzy-ref-1.html:255;100"> +<style> +div { + width: 99px; + height: 100px; + background-color: green; +} +</style> +<div></div> +
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt index 4f812297..a2c26dc 100644 --- a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt
@@ -23,7 +23,7 @@ PASS BarcodeDetector interface: existence and properties of interface prototype object PASS BarcodeDetector interface: existence and properties of interface prototype object's "constructor" property PASS BarcodeDetector interface: existence and properties of interface prototype object's @@unscopables property -FAIL BarcodeDetector interface: operation getSupportedFormats() assert_own_property: interface object missing static operation expected property "getSupportedFormats" missing +PASS BarcodeDetector interface: operation getSupportedFormats() PASS BarcodeDetector interface: operation detect(ImageBitmapSource) FAIL DetectedBarcode interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function() { new interface_object();
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt deleted file mode 100644 index 6d71cf9..0000000 --- a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -This is a testharness.js-based test. -PASS Test shape-detection IDL interface -PASS FaceDetector interface: existence and properties of interface object -PASS FaceDetector interface object length -PASS FaceDetector interface object name -PASS FaceDetector interface: existence and properties of interface prototype object -PASS FaceDetector interface: existence and properties of interface prototype object's "constructor" property -PASS FaceDetector interface: existence and properties of interface prototype object's @@unscopables property -PASS FaceDetector interface: operation detect(ImageBitmapSource) -PASS DetectedFace interface: existence and properties of interface object -PASS BarcodeDetector interface: existence and properties of interface object -PASS BarcodeDetector interface object length -PASS BarcodeDetector interface object name -PASS BarcodeDetector interface: existence and properties of interface prototype object -PASS BarcodeDetector interface: existence and properties of interface prototype object's "constructor" property -PASS BarcodeDetector interface: existence and properties of interface prototype object's @@unscopables property -FAIL BarcodeDetector interface: operation getSupportedFormats() assert_own_property: interface object missing static operation expected property "getSupportedFormats" missing -PASS BarcodeDetector interface: operation detect(ImageBitmapSource) -PASS DetectedBarcode interface: existence and properties of interface object -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py index c06daee3..c6363a70 100644 --- a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py +++ b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
@@ -1,5 +1,5 @@ from copy import copy - +from six import iteritems from six.moves.urllib.parse import urljoin, urlparse from abc import ABCMeta, abstractproperty @@ -169,6 +169,14 @@ def dpi(self): return self._extras.get("dpi") + @property + def fuzzy(self): + rv = self._extras.get("fuzzy", []) + if isinstance(rv, list): + return {tuple(item[0]): item[1] + for item in self._extras.get("fuzzy", [])} + return rv + def meta_key(self): return (self.timeout, self.viewport_size, self.dpi) @@ -181,6 +189,8 @@ extras["viewport_size"] = self.viewport_size if self.dpi is not None: extras["dpi"] = self.dpi + if self.fuzzy: + extras["fuzzy"] = list(iteritems(self.fuzzy)) return rv @classmethod
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py b/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py index b5d7cdf8..78843b0 100644 --- a/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py +++ b/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py
@@ -1,6 +1,7 @@ import hashlib import re import os +from collections import deque from six import binary_type from six.moves.urllib.parse import urljoin from fnmatch import fnmatch @@ -453,6 +454,79 @@ return self.dpi_nodes[0].attrib.get("content", None) @cached_property + def fuzzy_nodes(self): + """List of ElementTree Elements corresponding to nodes in a test that + specify reftest fuzziness""" + return self.root.findall(".//{http://www.w3.org/1999/xhtml}meta[@name='fuzzy']") + + @cached_property + def fuzzy(self): + rv = {} + if self.root is None: + return rv + + if not self.fuzzy_nodes: + return rv + + args = ["maxDifference", "totalPixels"] + + for node in self.fuzzy_nodes: + item = node.attrib.get("content", "") + + parts = item.rsplit(":", 1) + if len(parts) == 1: + key = None + value = parts[0] + else: + key = urljoin(self.url, parts[0]) + reftype = None + for ref in self.references: + if ref[0] == key: + reftype = ref[1] + break + if reftype not in ("==", "!="): + raise ValueError("Fuzzy key %s doesn't correspond to a references" % key) + key = (self.url, key, reftype) + value = parts[1] + ranges = value.split(";") + if len(ranges) != 2: + raise ValueError("Malformed fuzzy value %s" % item) + arg_values = {None: deque()} + for range_str_value in ranges: + if "=" in range_str_value: + name, range_str_value = [part.strip() + for part in range_str_value.split("=", 1)] + if name not in args: + raise ValueError("%s is not a valid fuzzy property" % name) + if arg_values.get(name): + raise ValueError("Got multiple values for argument %s" % name) + else: + name = None + if "-" in range_str_value: + range_min, range_max = range_str_value.split("-") + else: + range_min = range_str_value + range_max = range_str_value + try: + range_value = [int(x.strip()) for x in (range_min, range_max)] + except ValueError: + raise ValueError("Fuzzy value %s must be a range of integers" % + range_str_value) + if name is None: + arg_values[None].append(range_value) + else: + arg_values[name] = range_value + rv[key] = [] + for arg_name in args: + if arg_values.get(arg_name): + value = arg_values.pop(arg_name) + else: + value = arg_values[None].popleft() + rv[key].append(value) + assert list(arg_values.keys()) == [None] and len(arg_values[None]) == 0 + return rv + + @cached_property def testharness_nodes(self): """List of ElementTree Elements corresponding to nodes representing a testharness.js script""" @@ -749,7 +823,8 @@ references=self.references, timeout=self.timeout, viewport_size=self.viewport_size, - dpi=self.dpi + dpi=self.dpi, + fuzzy=self.fuzzy )] elif self.content_is_css_visual and not self.name_is_reference:
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt index 24a7d3d..37f4fde 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
@@ -2,4 +2,6 @@ mozinfo == 0.10 mozlog==4.0 mozdebug==0.1.1 +pillow == 5.2.0 urllib3[secure]==1.24.1 +
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py index 493d3c4..6563721 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py
@@ -202,11 +202,13 @@ def ensure_started(self): # Pause for a while to ensure that the server has a chance to start - for _ in xrange(60): + total_sleep_secs = 30 + each_sleep_secs = 0.01 + for _ in xrange(int(total_sleep_secs / each_sleep_secs)): failed = self.test_servers() if not failed: return - time.sleep(0.5) + time.sleep(each_sleep_secs) raise EnvironmentError("Servers failed to start: %s" % ", ".join("%s:%s" % item for item in failed))
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py index 8958ecf..5fa3056 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -1,6 +1,7 @@ import base64 import hashlib import httplib +import io import os import threading import traceback @@ -8,6 +9,8 @@ import urlparse from abc import ABCMeta, abstractmethod +from PIL import Image, ImageChops, ImageStat + from ..testrunner import Stop from protocol import Protocol, BaseProtocolPart @@ -286,8 +289,7 @@ screenshot = data hash_value = hash_screenshot(data) - - self.screenshot_cache[key] = (hash_value, None) + self.screenshot_cache[key] = (hash_value, screenshot) rv = (hash_value, screenshot) else: @@ -299,11 +301,32 @@ def reset(self): self.screenshot_cache.clear() - def is_pass(self, lhs_hash, rhs_hash, relation): + def is_pass(self, hashes, screenshots, relation, fuzzy): assert relation in ("==", "!=") - self.message.append("Testing %s %s %s" % (lhs_hash, relation, rhs_hash)) - return ((relation == "==" and lhs_hash == rhs_hash) or - (relation == "!=" and lhs_hash != rhs_hash)) + if not fuzzy or fuzzy == ((0,0), (0,0)): + equal = hashes[0] == hashes[1] + else: + max_per_channel, pixels_different = self.get_differences(screenshots) + allowed_per_channel, allowed_different = fuzzy + self.logger.info("Allowed %s pixels different, maximum difference per channel %s" % + ("-".join(str(item) for item in allowed_different), + "-".join(str(item) for item in allowed_per_channel))) + equal = (allowed_per_channel[0] <= max_per_channel <= allowed_per_channel[1] and + allowed_different[0] <= pixels_different <= allowed_different[1]) + return equal if relation == "==" else not equal + + def get_differences(self, screenshots): + lhs = Image.open(io.BytesIO(base64.b64decode(screenshots[0]))).convert("RGB") + rhs = Image.open(io.BytesIO(base64.b64decode(screenshots[1]))).convert("RGB") + diff = ImageChops.difference(lhs, rhs) + minimal_diff = diff.crop(diff.getbbox()) + mask = minimal_diff.convert("L", dither=None) + stat = ImageStat.Stat(minimal_diff, mask) + per_channel = max(item[1] for item in stat.extrema) + count = stat.count[0] + self.logger.info("Found %s pixels different, maximum difference per channel %s" % + (count, per_channel)) + return per_channel, count def run_test(self, test): viewport_size = test.viewport_size @@ -319,6 +342,7 @@ screenshots = [None, None] nodes, relation = stack.pop() + fuzzy = self.get_fuzzy(test, nodes, relation) for i, node in enumerate(nodes): success, data = self.get_hash(node, viewport_size, dpi) @@ -327,7 +351,8 @@ hashes[i], screenshots[i] = data - if self.is_pass(hashes[0], hashes[1], relation): + if self.is_pass(hashes, screenshots, relation, fuzzy): + fuzzy = self.get_fuzzy(test, nodes, relation) if nodes[1].references: stack.extend(list(((nodes[1], item[0]), item[1]) for item in reversed(nodes[1].references))) else: @@ -352,6 +377,25 @@ "message": "\n".join(self.message), "extra": {"reftest_screenshots": log_data}} + def get_fuzzy(self, root_test, test_nodes, relation): + full_key = tuple([item.url for item in test_nodes] + [relation]) + ref_only_key = test_nodes[1].url + + fuzzy_override = root_test.fuzzy_override + fuzzy = test_nodes[0].fuzzy + + sources = [fuzzy_override, fuzzy] + keys = [full_key, ref_only_key, None] + value = None + for source in sources: + for key in keys: + if key in source: + value = source[key] + break + if value: + break + return value + def retake_screenshot(self, node, viewport_size, dpi): success, data = self.executor.screenshot(node, viewport_size, dpi) if not success:
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py index b70f0ed0..f9fd97b 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -846,7 +846,7 @@ return screenshot -class InternalRefTestImplementation(object): +class InternalRefTestImplementation(RefTestImplementation): def __init__(self, executor): self.timeout_multiplier = executor.timeout_multiplier self.executor = executor @@ -870,7 +870,7 @@ pass def run_test(self, test): - references = self.get_references(test) + references = self.get_references(test, test) timeout = (test.timeout * 1000) * self.timeout_multiplier rv = self.executor.protocol.marionette._send_message("reftest:run", {"test": self.executor.test_url(test), @@ -881,10 +881,11 @@ "height": 600})["value"] return rv - def get_references(self, node): + def get_references(self, root_test, node): rv = [] for item, relation in node.references: - rv.append([self.executor.test_url(item), self.get_references(item), relation]) + rv.append([self.executor.test_url(item), self.get_references(root_test, item), relation, + {"fuzzy": self.get_fuzzy(root_test, [node, item], relation)}]) return rv def teardown(self):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py index 73f5fcf8..563252c 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -416,7 +416,11 @@ """return [window.outerWidth - window.innerWidth, window.outerHeight - window.innerHeight];""" ) - self.protocol.webdriver.window.position = (0, 0) + try: + self.protocol.webdriver.window.position = (0, 0) + except client.InvalidArgumentException: + # Safari 12 throws with 0 or 1, treating them as bools; fixed in STP + self.protocol.webdriver.window.position = (2, 2) self.protocol.webdriver.window.size = (800 + width_offset, 600 + height_offset) result = self.implementation.run_test(test)
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py index 80284bd8..fb3ef62 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py
@@ -1,5 +1,6 @@ import os import urlparse +from collections import deque from wptmanifest.backends import static from wptmanifest.backends.static import ManifestItem @@ -97,6 +98,105 @@ return rv +def fuzzy_prop(node): + """Fuzzy reftest match + + This can either be a list of strings or a single string. When a list is + supplied, the format of each item matches the description below. + + The general format is + fuzzy = [key ":"] <prop> ";" <prop> + key = <test name> [reftype <reference name>] + reftype = "==" | "!=" + prop = [propName "=" ] range + propName = "maxDifferences" | "totalPixels" + range = <digits> ["-" <digits>] + + So for example: + maxDifferences=10;totalPixels=10-20 + + specifies that for any test/ref pair for which no other rule is supplied, + there must be a maximum pixel difference of exactly 10, and betwen 10 and + 20 total pixels different. + + test.html==ref.htm:10;20 + + specifies that for a equality comparison between test.html and ref.htm, + resolved relative to the test path, there can be a maximum difference + of 10 in the pixel value for any channel and 20 pixels total difference. + + ref.html:10;20 + + is just like the above but applies to any comparison involving ref.html + on the right hand side. + + The return format is [(key, (maxDifferenceRange, totalPixelsRange))], where + the key is either None where no specific reference is specified, the reference + name where there is only one component or a tuple (test, ref, reftype) when the + exact comparison is specified. maxDifferenceRange and totalPixelsRange are tuples + of integers indicating the inclusive range of allowed values. +""" + rv = [] + args = ["maxDifference", "totalPixels"] + try: + value = node.get("fuzzy") + except KeyError: + return rv + if not isinstance(value, list): + value = [value] + for item in value: + if not isinstance(item, (str, unicode)): + rv.append(item) + continue + parts = item.rsplit(":", 1) + if len(parts) == 1: + key = None + fuzzy_values = parts[0] + else: + key, fuzzy_values = parts + for reftype in ["==", "!="]: + if reftype in key: + key = key.split(reftype) + key.append(reftype) + key = tuple(key) + ranges = fuzzy_values.split(";") + if len(ranges) != 2: + raise ValueError("Malformed fuzzy value %s" % item) + arg_values = {None: deque()} + for range_str_value in ranges: + if "=" in range_str_value: + name, range_str_value = [part.strip() + for part in range_str_value.split("=", 1)] + if name not in args: + raise ValueError("%s is not a valid fuzzy property" % name) + if arg_values.get(name): + raise ValueError("Got multiple values for argument %s" % name) + else: + name = None + if "-" in range_str_value: + range_min, range_max = range_str_value.split("-") + else: + range_min = range_str_value + range_max = range_str_value + try: + range_value = tuple(int(item.strip()) for item in (range_min, range_max)) + except ValueError: + raise ValueError("Fuzzy value %s must be a range of integers" % range_str_value) + if name is None: + arg_values[None].append(range_value) + else: + arg_values[name] = range_value + range_values = [] + for arg_name in args: + if arg_values.get(arg_name): + value = arg_values.pop(arg_name) + else: + value = arg_values[None].popleft() + range_values.append(value) + rv.append((key, tuple(range_values))) + return rv + + class ExpectedManifest(ManifestItem): def __init__(self, name, test_path, url_base): """Object representing all the tests in a particular manifest @@ -183,6 +283,10 @@ def lsan_max_stack_depth(self): return int_prop("lsan-max-stack-depth", self) + @property + def fuzzy(self): + return fuzzy_prop(self) + class DirectoryManifest(ManifestItem): @property @@ -229,6 +333,11 @@ def lsan_max_stack_depth(self): return int_prop("lsan-max-stack-depth", self) + @property + def fuzzy(self): + return fuzzy_prop(self) + + class TestNode(ManifestItem): def __init__(self, name): """Tree node associated with a particular test in a manifest @@ -301,6 +410,10 @@ def lsan_max_stack_depth(self): return int_prop("lsan-max-stack-depth", self) + @property + def fuzzy(self): + return fuzzy_prop(self) + def append(self, node): """Add a subtest to the current test
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py index 4eb292ef..7ad3575 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
@@ -341,6 +341,8 @@ yield item def remove_value(self, key, value): + if key not in self._data: + return try: self._data[key].remove(value) except ValueError:
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py index dc1c6b63..6a4fa4f 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py
@@ -1,5 +1,6 @@ import os import subprocess +import urlparse from collections import defaultdict from wptmanifest.parser import atoms @@ -279,12 +280,12 @@ @property def prefs(self): prefs = {} - for meta in self.itermeta(): + for meta in reversed(list(self.itermeta())): meta_prefs = meta.prefs - prefs.update(meta_prefs) if atom_reset in meta_prefs: - del prefs[atom_reset] - break + del meta_prefs[atom_reset] + prefs = {} + prefs.update(meta_prefs) return prefs def expected(self, subtest=None): @@ -359,7 +360,7 @@ test_type = "reftest" def __init__(self, tests_root, url, inherit_metadata, test_metadata, references, - timeout=None, path=None, viewport_size=None, dpi=None, protocol="http"): + timeout=None, path=None, viewport_size=None, dpi=None, fuzzy=None, protocol="http"): Test.__init__(self, tests_root, url, inherit_metadata, test_metadata, timeout, path, protocol) @@ -370,6 +371,7 @@ self.references = references self.viewport_size = viewport_size self.dpi = dpi + self._fuzzy = fuzzy or {} @classmethod def from_manifest(cls, @@ -398,7 +400,8 @@ path=manifest_test.path, viewport_size=manifest_test.viewport_size, dpi=manifest_test.dpi, - protocol="https" if hasattr(manifest_test, "https") and manifest_test.https else "http") + protocol="https" if hasattr(manifest_test, "https") and manifest_test.https else "http", + fuzzy=manifest_test.fuzzy) nodes[url] = node @@ -454,6 +457,30 @@ def keys(self): return ("reftype", "refurl") + @property + def fuzzy(self): + return self._fuzzy + + @property + def fuzzy_override(self): + values = {} + for meta in reversed(list(self.itermeta(None))): + value = meta.fuzzy + if not value: + continue + if atom_reset in value: + value.remove(atom_reset) + values = {} + for key, data in value: + if len(key) == 3: + key[0] = urlparse.urljoin(self.url, key[0]) + key[1] = urlparse.urljoin(self.url, key[1]) + else: + # Key is just a relative url to a ref + key = urlparse.urljoin(self.url, key) + values[key] = data + return values + class WdspecTest(Test):
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/images/rendering-broken-block-flow-images-expected.png index 1ce9e7d..3cb7975a 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/clipboard/async-write-blobs-read-blobs.html b/third_party/blink/web_tests/http/tests/clipboard/async-write-blobs-read-blobs.html new file mode 100644 index 0000000..6c64664 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/clipboard/async-write-blobs-read-blobs.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Async Clipboard write blobs -> read blobs tests +</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../resources/permissions-helper.js"></script> + +<script> +async function loadBlob(fileName) { + const fetched = await fetch(fileName); + return await fetched.blob(); +} + +promise_test(async t => { + await PermissionsHelper.setPermission('clipboard-read', 'granted'); + await PermissionsHelper.setPermission('clipboard-write', 'granted'); + + const blobText = new Blob(["test text"], {type: 'text/plain'}); + const blobImage = await loadBlob('resources/greenbox.png'); + + assert_equals(blobText.type, "text/plain"); + assert_equals(blobImage.type, "image/png"); + + await navigator.clipboard.write([blobText, blobImage]); + const output = await navigator.clipboard.read(); + + assert_equals(output.length, 2); + assert_equals(output[0].type, "text/plain"); + assert_equals(output[1].type, "image/png"); +}, "Verify write and read clipboard (multiple blobs)"); +</script>
diff --git a/third_party/blink/web_tests/http/tests/clipboard/async-write-image-read-image.html b/third_party/blink/web_tests/http/tests/clipboard/async-write-image-read-image.html index 86e06f6..1e8c4a80 100644 --- a/third_party/blink/web_tests/http/tests/clipboard/async-write-image-read-image.html +++ b/third_party/blink/web_tests/http/tests/clipboard/async-write-image-read-image.html
@@ -41,19 +41,21 @@ await PermissionsHelper.setPermission('clipboard-read', 'granted'); await PermissionsHelper.setPermission('clipboard-write', 'granted'); - const input = await loadBlob('resources/greenbox.png'); + const blobInput = await loadBlob('resources/greenbox.png'); - assert_equals(input.type, "image/png"); - await navigator.clipboard.write(input); - const output = await navigator.clipboard.read(); - assert_equals(output.type, "image/png"); + assert_equals(blobInput.type, "image/png"); + await navigator.clipboard.write([blobInput]); + const blobsOutput = await navigator.clipboard.read(); + assert_equals(blobsOutput.length, 1); + const blobOutput = blobsOutput[0]; + assert_equals(blobOutput.type, "image/png"); document.getElementById('image-on-clipboard').src = - window.URL.createObjectURL(output); + window.URL.createObjectURL(blobOutput); - const comparableInput = await getBitmapString(input); - const comparableOutput = await getBitmapString(output); + const comparableInput = await getBitmapString(blobInput); + const comparableOutput = await getBitmapString(blobOutput); assert_equals(comparableOutput, comparableInput); -}, "Verify write and read clipboard (DOMString)"); +}, "Verify write and read clipboard (image/png Blob)"); </script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt index e04db1d..9ffee3a9 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/filter-matched-styles-expected.txt
@@ -65,7 +65,6 @@ display: block } html { - display: block color: -internal-root-color }
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt index 2f4328d2..3aab58d 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators-expected.txt
@@ -21,7 +21,6 @@ display: block } html { - display: block color: -internal-root-color } #third::before { @@ -52,7 +51,7 @@ Filtering styles by: display [ HIDDEN ] Inherited from div#second [ VISIBLE ] Inherited from div#first -[ VISIBLE ] Inherited from html +[ HIDDEN ] Inherited from html [ HIDDEN ] Pseudo ::before element [ VISIBLE ] Pseudo ::after element
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt index 23c16d4..9a9c19f2 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-update-links-4-expected.txt
@@ -13,7 +13,7 @@ element.style { () [expanded] -article, aside, footer, header, hgroup, main, nav, section { (user agent stylesheet) +section { (user agent stylesheet) display: block; ======== Inherited from html ========
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt index e5f8d2e6..7a9e368 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/svg-style-expected.txt
@@ -12,7 +12,7 @@ svg:rect[Attributes Style] { () [expanded] -:not(svg), :not(foreignObject) > svg { (user agent stylesheet) +:not(svg) { (user agent stylesheet) transform-origin: 0px 0px; ======== Inherited from html ========
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile-expected.txt b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile-expected.txt new file mode 100644 index 0000000..392a6c2 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile-expected.txt
@@ -0,0 +1,5 @@ +Tests that the live line-level heap profile is shown in the text editor. + +allocator.js +Memory annotation added to line 12. +
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js new file mode 100644 index 0000000..09ed03d7 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js
@@ -0,0 +1,29 @@ +// Copyright 2019 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. + +(async function() { + TestRunner.addResult(`Tests that the live line-level heap profile is shown in the text editor.\n`); + await self.runtime.loadModulePromise('perf_ui'); + await PerfUI.LiveHeapProfile.hasStartedForTest(); + await TestRunner.loadModule('sources_test_runner'); + await TestRunner.showPanel('sources'); + + await TestRunner.evaluateInPagePromise(` + let dump = new Array(10000).fill(42).map(x => Date.now() + '42'); + //# sourceURL=allocator.js`); + + TestRunner.addSniffer(SourceFrame.SourcesTextEditor.prototype, 'setGutterDecoration', decorationAdded, true); + SourcesTestRunner.showScriptSource('allocator.js', frameRevealed); + + function decorationAdded(line, type, element) { + if (line !== 12 || type !== 'CodeMirror-gutter-memory' || !element.textContent || !element.style.backgroundColor) + return; + TestRunner.addResult(`Memory annotation added to line ${line}.`); + TestRunner.completeTest(); + } + + function frameRevealed(frame) { + TestRunner.addResult(TestRunner.formatters.formatAsURL(frame.uiSourceCode().url())); + } +})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt index bef9e0b..842c89dc 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
@@ -1,11 +1,11 @@ Tests that a line-level CPU profile is shown in the text editor. .../devtools/tracing/resources/empty.js -99 CodeMirror-gutter-performance 10.0ms rgba(255, 187, 0, 0.263) -101 CodeMirror-gutter-performance 1900.0ms rgba(255, 187, 0, 0.718) -0 CodeMirror-gutter-performance 100.0ms rgba(255, 187, 0, 0.463) -1 CodeMirror-gutter-performance 200.0ms rgba(255, 187, 0, 0.52) -2 CodeMirror-gutter-performance 300.0ms rgba(255, 187, 0, 0.557) -3 CodeMirror-gutter-performance 400.0ms rgba(255, 187, 0, 0.58) -54 CodeMirror-gutter-performance 220.0ms rgba(255, 187, 0, 0.53) +99 CodeMirror-gutter-performance 10.0ms rgba(255, 187, 0, 0.4) +101 CodeMirror-gutter-performance 1900.0ms rgba(255, 187, 0, 0.855) +0 CodeMirror-gutter-performance 100.0ms rgba(255, 187, 0, 0.6) +1 CodeMirror-gutter-performance 200.0ms rgba(255, 187, 0, 0.66) +2 CodeMirror-gutter-performance 300.0ms rgba(255, 187, 0, 0.694) +3 CodeMirror-gutter-performance 400.0ms rgba(255, 187, 0, 0.72) +54 CodeMirror-gutter-performance 220.0ms rgba(255, 187, 0, 0.67)
diff --git a/third_party/blink/web_tests/http/tests/images/restyle-decode-error.html b/third_party/blink/web_tests/http/tests/images/restyle-decode-error.html index b774e2b..4bb9ed20 100644 --- a/third_party/blink/web_tests/http/tests/images/restyle-decode-error.html +++ b/third_party/blink/web_tests/http/tests/images/restyle-decode-error.html
@@ -1,5 +1,7 @@ <html> -<body> +<!-- Avoid scrollbars; we'd get a scrollbar otherwise, because the (broken and + invisible) image is quite large. --> +<body style="overflow:hidden;"> <img style="content: url(#MyFilter); display: block;"> <script> setTimeout(function() {
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html deleted file mode 100644 index d6d96c3..0000000 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html +++ /dev/null
@@ -1,36 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<!-- Generate token with the command: -generate_token.py http://127.0.0.1:8000 BackgroundFetch --expire-timestamp=2000000000 ---> - -<meta http-equiv="origin-trial" content="AtDl/AukAuUX0Sw7KRz+mrV2vpSYrfDyVS4vdO3I1clqoNgKGqCX5Np5KIhlC6oQl8XcULXJz5bc9Y4CcYj9xA4AAABXeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQmFja2dyb3VuZEZldGNoIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9" /> -<title>Background Fetch API - interfaces exposed by origin trial</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/origin-trials-helper.js"></script> -<script src="/serviceworker/resources/test-helpers.js"></script> -<script> - -test(t => { - OriginTrialsHelper.check_properties(this, { - 'BackgroundFetchManager': ['fetch', 'get', 'getIds'], - 'BackgroundFetchUpdateUIEvent': ['updateUI'], - 'BackgroundFetchRegistration': ['id', 'uploadTotal', 'uploaded', - 'downloadTotal', 'downloaded', 'result', - 'failureReason', 'recordsAvailable', - 'onprogress', 'match', 'matchAll'], - 'ServiceWorkerRegistration': ['backgroundFetch'], - }); -}, 'Background Fetch API interfaces and properties in Origin-Trial enabled document.'); - -fetch_tests_from_worker(new Worker('resources/backgroundfetch-origin-trial-interfaces-worker.js')); - -// Only run "disabled" tests if the feature is not enabled via runtime flags. -if (!self.internals.runtimeFlags.backgroundFetchEnabled) { - service_worker_test('resources/backgroundfetch-origin-trial-interfaces-serviceworker-disabled.js'); -} - -service_worker_test('resources/backgroundfetch-origin-trial-interfaces-serviceworker-enabled.php'); - -</script>
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-disabled.js b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-disabled.js deleted file mode 100644 index 4438be84..0000000 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-disabled.js +++ /dev/null
@@ -1,12 +0,0 @@ -importScripts('/resources/testharness.js', - '/resources/origin-trials-helper.js'); - -test(t => { - OriginTrialsHelper.check_interfaces_missing( - self, - ['BackgroundFetchEvent', 'BackgroundFetchFetch', 'BackgroundFetchManager', - 'BackgroundFetchUpdateUIEvent', 'BackgroundFetchRecord', - 'BackgroundFetchRegistration']); -}, 'Background Fetch API interfaces in Origin-Trial disabled worker.'); - -done();
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-enabled.php b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-enabled.php deleted file mode 100644 index 438a3993..0000000 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-serviceworker-enabled.php +++ /dev/null
@@ -1,32 +0,0 @@ -<?php -// Generate token with the command: -// generate_token.py http://127.0.0.1:8000 BackgroundFetch --expire-timestamp=2000000000 -header('Origin-Trial: AtDl/AukAuUX0Sw7KRz+mrV2vpSYrfDyVS4vdO3I1clqoNgKGqCX5Np5KIhlC6oQl8XcULXJz5bc9Y4CcYj9xA4AAABXeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQmFja2dyb3VuZEZldGNoIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9'); -header('Content-Type: application/javascript'); -?> -importScripts('/resources/testharness.js', - '/resources/origin-trials-helper.js'); - -test(t => { - OriginTrialsHelper.check_properties(this, { - 'ServiceWorkerRegistration': ['backgroundFetch'], - 'BackgroundFetchManager': ['fetch', 'get', 'getIds'], - 'BackgroundFetchEvent': ['registration'], - 'BackgroundFetchUpdateUIEvent': ['updateUI'], - 'BackgroundFetchRecord': ['request', 'responseReady'], - 'BackgroundFetchRegistration': ['id', 'uploadTotal', 'uploaded', - 'downloadTotal', 'downloaded', 'result', - 'failureReason', 'recordsAvailable', - 'onprogress', 'abort', 'match', 'matchAll'], - }); -}); - -test(t => { - assert_true('onbackgroundfetchsuccess' in self, 'onbackgroundfetchsuccess property exists on global'); - assert_true('onbackgroundfetchfail' in self, 'onbackgroundfetchfail property exists on global'); - assert_true('onbackgroundfetchabort' in self, 'onbackgroundfetchabort property exists on global'); - assert_true('onbackgroundfetchclick' in self, 'onbackgroundfetchclick property exists on global'); - -}, 'Background Fetch API entry points in Origin-Trial enabled serviceworker.'); - -done();
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js deleted file mode 100644 index b885bf6..0000000 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js +++ /dev/null
@@ -1,16 +0,0 @@ -importScripts('/resources/testharness.js', - '/resources/origin-trials-helper.js'); - -test(t => { - - OriginTrialsHelper.check_properties(this, { - 'ServiceWorkerRegistration': ['backgroundFetch'], - 'BackgroundFetchManager': ['fetch', 'get', 'getIds'], - 'BackgroundFetchRegistration': ['id', 'uploadTotal', 'uploaded', - 'downloadTotal', 'downloaded', 'result', - 'failureReason', 'recordsAvailable', - 'onprogress'], - }); -}, 'Background Fetch API interfaces in an Origin-Trial enabled worker.'); - -done();
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 39730843..66eb4c3 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -50,6 +50,7 @@ method constructor method updateUI interface BarcodeDetector + static method getSupportedFormats attribute @@toStringTag method constructor method detect @@ -1310,6 +1311,7 @@ attribute ACTIVE_VARIABLES attribute ALIASED_LINE_WIDTH_RANGE attribute ALIASED_POINT_SIZE_RANGE + attribute ALL_BARRIER_BITS attribute ALPHA attribute ALPHA_BITS attribute ALREADY_SIGNALED
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt deleted file mode 100644 index 1d304732..0000000 --- a/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL opener of discarded nested browsing context openerGet is not a function -FAIL opener of discarded auxiliary browsing context openerGet is not a function -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/linux/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/platform/linux/images/rendering-broken-block-flow-images-expected.png index 87ed1dd..485be0f 100644 --- a/third_party/blink/web_tests/platform/linux/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/platform/linux/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png index 8326e8da6..42fa90e 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.png index 0e7bcef..dc32f49 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt deleted file mode 100644 index 1d304732..0000000 --- a/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL opener of discarded nested browsing context openerGet is not a function -FAIL opener of discarded auxiliary browsing context openerGet is not a function -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/win/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/platform/win/images/rendering-broken-block-flow-images-expected.png index c051414a..3818f8bb 100644 --- a/third_party/blink/web_tests/platform/win/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/platform/win/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png index c7fee50..51ac7d9e 100644 --- a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt deleted file mode 100644 index 1d304732..0000000 --- a/third_party/blink/web_tests/platform/win7/external/wpt/html/browsers/windows/embedded-opener-remove-frame-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL opener of discarded nested browsing context openerGet is not a function -FAIL opener of discarded auxiliary browsing context openerGet is not a function -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/shapedetection/detection-support.html b/third_party/blink/web_tests/shapedetection/detection-support.html new file mode 100644 index 0000000..f8968b07 --- /dev/null +++ b/third_party/blink/web_tests/shapedetection/detection-support.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<link rel="help" href="https://wicg.github.io/shape-detection-api/#dom-barcodedetector-getsupportedformats"> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> +<script src="file:///gen/services/shape_detection/public/mojom/barcodedetection.mojom.js"></script> +<script src="file:///gen/services/shape_detection/public/mojom/barcodedetection_provider.mojom.js"></script> +<script src="resources/mock-barcodedetection.js"></script> +<script> +'use strict'; + +promise_test(() => { + return new Promise((resolve, reject) => { + var formats = BarcodeDetector.getSupportedFormats(); + resolve(formats); + }).then(result => { + assert_equals(result.length, 3, 'Number of supported formats'); + assert_equals(result[0], 'aztec', 'format 1'); + assert_equals(result[1], 'data_matrix', 'format 2'); + assert_equals(result[2], 'qr_code', 'format 3'); + }); +}, 'get supported barcode formats'); + +</script>
diff --git a/third_party/blink/web_tests/shapedetection/resources/mock-barcodedetection.js b/third_party/blink/web_tests/shapedetection/resources/mock-barcodedetection.js index 21ea5f55..b542ca5 100644 --- a/third_party/blink/web_tests/shapedetection/resources/mock-barcodedetection.js +++ b/third_party/blink/web_tests/shapedetection/resources/mock-barcodedetection.js
@@ -16,6 +16,16 @@ this.mockService_ = new MockBarcodeDetection(request, options); } + enumerateSupportedFormats() { + return Promise.resolve({ + supportedFormats: [ + shapeDetection.mojom.BarcodeFormat.AZTEC, + shapeDetection.mojom.BarcodeFormat.DATA_MATRIX, + shapeDetection.mojom.BarcodeFormat.QR_CODE, + ] + }); + } + getFrameData() { return this.mockService_.bufferData_; }
diff --git a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/claim-worker-fetch.https-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/claim-worker-fetch.https-expected.txt new file mode 100644 index 0000000..757707b6 --- /dev/null +++ b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/claim-worker-fetch.https-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL fetch() in Worker should be intercepted after the client is claimed. assert_equals: fetch() in the worker should be intercepted. expected "Intercepted!" but got "a simple text file\n" +FAIL fetch() in nested Worker should be intercepted after the client is claimed. assert_equals: fetch() in the worker should be intercepted. expected "Intercepted!" but got "a simple text file\n" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/local-url-inherit-controller.https-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/local-url-inherit-controller.https-expected.txt new file mode 100644 index 0000000..c7fc4ea --- /dev/null +++ b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/local-url-inherit-controller.https-expected.txt
@@ -0,0 +1,10 @@ +This is a testharness.js-based test. +FAIL Same-origin blob URL iframe should inherit service worker controller. assert_equals: blob URL iframe should inherit controller expected (string) "https://web-platform.test:8444/service-workers/service-worker/resources/local-url-inherit-controller-worker.js" but got (object) null +FAIL Same-origin blob URL iframe should intercept fetch(). assert_equals: blob URL iframe should intercept fetch expected "intercepted" but got "Hello world\n" +FAIL Same-origin blob URL worker should inherit service worker controller. promise_test: Unhandled rejection with value: "Uncaught TypeError: Cannot read property 'controller' of undefined" +FAIL Same-origin blob URL worker should intercept fetch(). assert_equals: blob URL worker should intercept fetch expected "intercepted" but got "Hello world\n" +PASS Data URL iframe should not intercept fetch(). +FAIL Data URL worker should not inherit service worker controller. promise_test: Unhandled rejection with value: "Uncaught TypeError: Cannot read property 'controller' of undefined" +PASS Data URL worker should not intercept fetch(). +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index ec0a5dda..65c2b06 100644 --- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -14,6 +14,41 @@ getter onabort method constructor setter onabort +interface BackgroundFetchEvent : ExtendableEvent + attribute @@toStringTag + getter registration + method constructor +interface BackgroundFetchManager + attribute @@toStringTag + method constructor + method fetch + method get + method getIds +interface BackgroundFetchRecord + attribute @@toStringTag + getter request + getter responseReady + method constructor +interface BackgroundFetchRegistration : EventTarget + attribute @@toStringTag + getter downloadTotal + getter downloaded + getter failureReason + getter id + getter onprogress + getter recordsAvailable + getter result + getter uploadTotal + getter uploaded + method abort + method constructor + method match + method matchAll + setter onprogress +interface BackgroundFetchUpdateUIEvent : BackgroundFetchEvent + attribute @@toStringTag + method constructor + method updateUI interface Blob attribute @@toStringTag getter size @@ -1021,6 +1056,7 @@ interface ServiceWorkerRegistration : EventTarget attribute @@toStringTag getter active + getter backgroundFetch getter installing getter navigationPreload getter onupdatefound @@ -2527,6 +2563,10 @@ getter clients getter onabortpayment getter onactivate + getter onbackgroundfetchabort + getter onbackgroundfetchclick + getter onbackgroundfetchfail + getter onbackgroundfetchsuccess getter oncanmakepayment getter onfetch getter oninstall @@ -2542,6 +2582,10 @@ method skipWaiting setter onabortpayment setter onactivate + setter onbackgroundfetchabort + setter onbackgroundfetchclick + setter onbackgroundfetchfail + setter onbackgroundfetchsuccess setter oncanmakepayment setter onfetch setter oninstall
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index d2429750..db855c8 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -15,6 +15,33 @@ [Worker] getter onabort [Worker] method constructor [Worker] setter onabort +[Worker] interface BackgroundFetchManager +[Worker] attribute @@toStringTag +[Worker] method constructor +[Worker] method fetch +[Worker] method get +[Worker] method getIds +[Worker] interface BackgroundFetchRecord +[Worker] attribute @@toStringTag +[Worker] getter request +[Worker] getter responseReady +[Worker] method constructor +[Worker] interface BackgroundFetchRegistration : EventTarget +[Worker] attribute @@toStringTag +[Worker] getter downloadTotal +[Worker] getter downloaded +[Worker] getter failureReason +[Worker] getter id +[Worker] getter onprogress +[Worker] getter recordsAvailable +[Worker] getter result +[Worker] getter uploadTotal +[Worker] getter uploaded +[Worker] method abort +[Worker] method constructor +[Worker] method match +[Worker] method matchAll +[Worker] setter onprogress [Worker] interface Blob [Worker] attribute @@toStringTag [Worker] getter size @@ -961,6 +988,7 @@ [Worker] interface ServiceWorkerRegistration : EventTarget [Worker] attribute @@toStringTag [Worker] getter active +[Worker] getter backgroundFetch [Worker] getter installing [Worker] getter navigationPreload [Worker] getter onupdatefound
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index c8f0635..8521df8 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -228,6 +228,33 @@ attribute @@toStringTag getter clientDataJSON method constructor +interface BackgroundFetchManager + attribute @@toStringTag + method constructor + method fetch + method get + method getIds +interface BackgroundFetchRecord + attribute @@toStringTag + getter request + getter responseReady + method constructor +interface BackgroundFetchRegistration : EventTarget + attribute @@toStringTag + getter downloadTotal + getter downloaded + getter failureReason + getter id + getter onprogress + getter recordsAvailable + getter result + getter uploadTotal + getter uploaded + method abort + method constructor + method match + method matchAll + setter onprogress interface BarProp attribute @@toStringTag getter visible @@ -6362,6 +6389,7 @@ interface ServiceWorkerRegistration : EventTarget attribute @@toStringTag getter active + getter backgroundFetch getter installing getter navigationPreload getter onupdatefound
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index cb5b1c9..3fa7246 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -15,6 +15,33 @@ [Worker] getter onabort [Worker] method constructor [Worker] setter onabort +[Worker] interface BackgroundFetchManager +[Worker] attribute @@toStringTag +[Worker] method constructor +[Worker] method fetch +[Worker] method get +[Worker] method getIds +[Worker] interface BackgroundFetchRecord +[Worker] attribute @@toStringTag +[Worker] getter request +[Worker] getter responseReady +[Worker] method constructor +[Worker] interface BackgroundFetchRegistration : EventTarget +[Worker] attribute @@toStringTag +[Worker] getter downloadTotal +[Worker] getter downloaded +[Worker] getter failureReason +[Worker] getter id +[Worker] getter onprogress +[Worker] getter recordsAvailable +[Worker] getter result +[Worker] getter uploadTotal +[Worker] getter uploaded +[Worker] method abort +[Worker] method constructor +[Worker] method match +[Worker] method matchAll +[Worker] setter onprogress [Worker] interface Blob [Worker] attribute @@toStringTag [Worker] getter size @@ -956,6 +983,7 @@ [Worker] interface ServiceWorkerRegistration : EventTarget [Worker] attribute @@toStringTag [Worker] getter active +[Worker] getter backgroundFetch [Worker] getter installing [Worker] getter navigationPreload [Worker] getter onupdatefound
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 8163fa72..4549102 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -43,6 +43,7 @@ [Worker] method matchAll [Worker] setter onprogress [Worker] interface BarcodeDetector +[Worker] static method getSupportedFormats [Worker] attribute @@toStringTag [Worker] method constructor [Worker] method detect @@ -1362,6 +1363,7 @@ [Worker] attribute ACTIVE_VARIABLES [Worker] attribute ALIASED_LINE_WIDTH_RANGE [Worker] attribute ALIASED_POINT_SIZE_RANGE +[Worker] attribute ALL_BARRIER_BITS [Worker] attribute ALPHA [Worker] attribute ALPHA_BITS [Worker] attribute ALREADY_SIGNALED
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 0ae5b01..908c3fa 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -452,6 +452,7 @@ getter visible method constructor interface BarcodeDetector + static method getSupportedFormats attribute @@toStringTag method constructor method detect @@ -8060,6 +8061,7 @@ attribute ACTIVE_VARIABLES attribute ALIASED_LINE_WIDTH_RANGE attribute ALIASED_POINT_SIZE_RANGE + attribute ALL_BARRIER_BITS attribute ALPHA attribute ALPHA_BITS attribute ALREADY_SIGNALED
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index 22af926..fe76c974 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -43,6 +43,7 @@ [Worker] method matchAll [Worker] setter onprogress [Worker] interface BarcodeDetector +[Worker] static method getSupportedFormats [Worker] attribute @@toStringTag [Worker] method constructor [Worker] method detect @@ -1228,6 +1229,7 @@ [Worker] attribute ACTIVE_VARIABLES [Worker] attribute ALIASED_LINE_WIDTH_RANGE [Worker] attribute ALIASED_POINT_SIZE_RANGE +[Worker] attribute ALL_BARRIER_BITS [Worker] attribute ALPHA [Worker] attribute ALPHA_BITS [Worker] attribute ALREADY_SIGNALED
diff --git a/third_party/flatbuffers/BUILD.gn b/third_party/flatbuffers/BUILD.gn index 1cbc22d..1c389cc 100644 --- a/third_party/flatbuffers/BUILD.gn +++ b/third_party/flatbuffers/BUILD.gn
@@ -17,6 +17,10 @@ "src/include/flatbuffers/stl_emulation.h", ] + if (is_win) { + data_deps = [ "//build/win:runtime_libs" ] + } + configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ]
diff --git a/third_party/ink/ink_resources.grd b/third_party/ink/ink_resources.grd index 4c7a2b9..3d2e058 100644 --- a/third_party/ink/ink_resources.grd +++ b/third_party/ink/ink_resources.grd
@@ -12,8 +12,10 @@ <includes> <if expr="chromeos"> <include name="IDR_INK_LIB_BINARY_JS" file="build/ink_lib_binary.js" type="BINDATA" /> - <include name="IDR_INK_GLCORE_BASE_WASM" file="build/wasm/glcore_base.wasm" compress="gzip" type="BINDATA" /> - <include name="IDR_INK_GLCORE_WASM_BOOTSTRAP_COMPILED_JS" file="build/wasm/glcore_wasm_bootstrap_compiled.js" type="BINDATA" /> + <include name="IDR_INK_PTHREAD_MAIN_JS" file="build/wasm-threads/pthread-main.js" type="BINDATA" /> + <include name="IDR_INK_GLCORE_BASE_WASM" file="build/wasm-threads/glcore_base.wasm" compress="gzip" type="BINDATA" /> + <include name="IDR_INK_GLCORE_BASE_JS_MEM" file="build/wasm-threads/glcore_base.js.mem" compress="gzip" type="BINDATA" /> + <include name="IDR_INK_GLCORE_WASM_BOOTSTRAP_COMPILED_JS" file="build/wasm-threads/glcore_wasm_bootstrap_compiled.js" type="BINDATA" /> </if> </includes> </release>
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 2f8f38f..331f07e5 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@ License File: source/libvpx/LICENSE Security Critical: yes -Date: Tuesday March 05 2019 +Date: Thursday March 07 2019 Branch: master -Commit: d64e328624e09cbc36e7077598bf0ff367dcdb4c +Commit: 8256c8b297c8b7c7ee4de24edff82ed67d6ef207 Description: Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni index 376acb9..13614df 100644 --- a/third_party/libvpx/libvpx_srcs.gni +++ b/third_party/libvpx/libvpx_srcs.gni
@@ -444,7 +444,8 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_sse2.c", "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_4t_intrin_sse2.c", ] -libvpx_srcs_x86_sse3 = [] +libvpx_srcs_x86_sse3 = [ +] libvpx_srcs_x86_ssse3 = [ "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c", "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c", @@ -480,7 +481,8 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_avx2.c", "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c", ] -libvpx_srcs_x86_avx512 = [] +libvpx_srcs_x86_avx512 = [ +] libvpx_srcs_x86_64 = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -895,8 +897,9 @@ "//third_party/libvpx/source/libvpx/vpx_ports/emms_mmx.asm", "//third_party/libvpx/source/libvpx/vpx_ports/float_control_word.asm", ] -libvpx_srcs_x86_64_mmx = - [ "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_mmx.c" ] +libvpx_srcs_x86_64_mmx = [ + "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_mmx.c", +] libvpx_srcs_x86_64_sse2 = [ "//third_party/libvpx/source/libvpx/vp8/common/x86/bilinear_filter_sse2.c", "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_sse2.c", @@ -927,7 +930,8 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_sse2.c", "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_4t_intrin_sse2.c", ] -libvpx_srcs_x86_64_sse3 = [] +libvpx_srcs_x86_64_sse3 = [ +] libvpx_srcs_x86_64_ssse3 = [ "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c", "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c", @@ -963,7 +967,8 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_avx2.c", "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c", ] -libvpx_srcs_x86_64_avx512 = [] +libvpx_srcs_x86_64_avx512 = [ +] libvpx_srcs_arm = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -1306,7 +1311,8 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_arm_assembly = [] +libvpx_srcs_arm_assembly = [ +] libvpx_srcs_arm_neon = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -2564,7 +2570,8 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_arm64_assembly = [] +libvpx_srcs_arm64_assembly = [ +] libvpx_srcs_arm_neon_highbd = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -3429,7 +3436,8 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_arm64_highbd_assembly = [] +libvpx_srcs_arm64_highbd_assembly = [ +] libvpx_srcs_mips = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -3771,7 +3779,8 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_mips_assembly = [] +libvpx_srcs_mips_assembly = [ +] libvpx_srcs_nacl = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -4112,7 +4121,8 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_nacl_assembly = [] +libvpx_srcs_nacl_assembly = [ +] libvpx_srcs_generic = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", @@ -4453,4 +4463,5 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h", ] -libvpx_srcs_generic_assembly = [] +libvpx_srcs_generic_assembly = [ +]
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index 88749942..bde94740 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 8 #define VERSION_PATCH 0 -#define VERSION_EXTRA "203-gd64e328624" +#define VERSION_EXTRA "207-g8256c8b29" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.8.0-203-gd64e328624" -#define VERSION_STRING " v1.8.0-203-gd64e328624" +#define VERSION_STRING_NOSP "v1.8.0-207-g8256c8b29" +#define VERSION_STRING " v1.8.0-207-g8256c8b29"
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn index 84ce0a6c..8e02f217 100644 --- a/third_party/protobuf/BUILD.gn +++ b/third_party/protobuf/BUILD.gn
@@ -222,10 +222,6 @@ # The SQLite fuzzer's corpus generator needs protobuf_full and is not # included in Chrome. "//third_party/sqlite:sqlite3_lpm_corpus_gen", - - # Some tests inside ChromeOS need reflection to parse golden files. - # Not included in production code. - "//chrome/browser/chromeos:time_limit_tests", ] sources = protobuf_lite_sources + [
diff --git a/third_party/sqlite/README.chromium b/third_party/sqlite/README.chromium index af2cd26..8a2fb275 100644 --- a/third_party/sqlite/README.chromium +++ b/third_party/sqlite/README.chromium
@@ -116,6 +116,18 @@ git rm patches/* git format-patch --output-directory=patches --zero-commit \ sqlite-base..sqlite-dev + +### Document and link any backported patches to the upstream repository URL +### and crbug. +# Under the *.patch's added by this change, the below information should be +# added between the "Subject: *" line and the first "---" line. For an example, +# please reference https://crrev.com/c/1480822/2/third_party/sqlite/patches/0008-Adjustments-to-the-page-cache-to-try-to-avoid-harmle.patch. +# +# This backports https://www.sqlite.org/src/info/XXX +# +# Bug: XXX + +### Commit and create CL git add amalgamation/ git add patches/ git commit -m "Squash: regenerate amalgamation and patches."
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 94276ce..c66b6eb 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -370,7 +370,6 @@ 'GPU FYI Win Builder': 'gpu_fyi_tests_release_trybot_x86', 'GPU FYI Win Builder (dbg)': 'gpu_fyi_tests_debug_trybot_x86', 'GPU FYI Win dEQP Builder': 'deqp_release_trybot_x86', - 'GPU FYI Win Clang Builder (dbg)': 'gpu_fyi_tests_win_clang_debug_bot', 'GPU FYI Win x64 Builder': 'gpu_fyi_tests_release_trybot', 'GPU FYI Win x64 Builder (dbg)': 'gpu_fyi_tests_debug_trybot', 'GPU FYI Win x64 dEQP Builder': 'deqp_release_trybot', @@ -1428,10 +1427,6 @@ 'gpu_fyi_tests', 'release_trybot', 'x86', ], - 'gpu_fyi_tests_win_clang_debug_bot': [ - 'gpu_tests', 'internal_gles_conform_tests', 'clang', 'debug_bot', 'minimal_symbols', - ], - 'gpu_tests_android_release_bot_minimal_symbols_arm64': [ 'android', 'release_bot', 'minimal_symbols', 'arm64', 'strip_debug_info', 'static_angle',
diff --git a/tools/metrics/actions/README.md b/tools/metrics/actions/README.md index 6361c038..daed02c 100644 --- a/tools/metrics/actions/README.md +++ b/tools/metrics/actions/README.md
@@ -152,12 +152,26 @@ ### Owners -User actions need to be owned by a person or set of people. These indicate who -the current experts on it are. Being the owner means you are responsible for -answering questions about it, handling the maintenance if there are functional -changes. The owners should be added in the original user action description. -If you are using a user action heavily and understand it intimately, feel free -to add yourself as an owner. @chromium.org email addresses are preferred. +User actions need to have owners, who are the current experts on the metric. The +owners are the contact points for any questions or maintenance tasks. It's a +best practice to list multiple owners, so that there's no single point of +failure for such communication. + +Being an owner means you are responsible for answering questions about the +metric, handling the maintenance if there are functional changes, and +deprecating the metric if it outlives its usefulness. If you are using a metric +heavily and understand it intimately, feel free to add yourself as an owner. +@chromium.org email addresses are preferred. + +If an appropriate mailing list is available, it's a good idea to include the +mailing list as a secondary owner. However, it's always a best practice to list +an individual as the primary owner. Listing an individual owner makes it clearer +who is ultimately most responsible for maintaining the metric, which makes it +less likely that such maintenance tasks will slip through the cracks. + +Notably, owners are asked to evaluate whether histograms have outlived their +usefulness. The metrics team may file a bug in Monorail. It's important that +somebody familiar with the user action notices and triages such bugs! ### Beware `not_user_triggered="true"`
diff --git a/tools/metrics/histograms/README.md b/tools/metrics/histograms/README.md index 9b32990d..d975abca 100644 --- a/tools/metrics/histograms/README.md +++ b/tools/metrics/histograms/README.md
@@ -32,9 +32,9 @@ When using histogram macros (calls such as `UMA_HISTOGRAM_ENUMERATION`), you're not allow to construct your string dynamically so that it can vary at a -callsite. At a given callsite (preferably you have only one), the string should -be the same every time the macro is called. If you need to use dynamic names, -use the functions in histogram_functions.h instead of the macros. +callsite. At a given callsite (preferably you have only one), the string +should be the same every time the macro is called. If you need to use dynamic +names, use the functions in histogram_functions.h instead of the macros. ### Don't Use Same String in Multiple Places @@ -402,14 +402,27 @@ ### Owners -Histograms need to be owned by a person or set of people. These indicate who -the current experts on this metric are. Being the owner means you are -responsible for answering questions about the metric, handling the maintenance -if there are functional changes, and deprecating the metric if it outlives its -usefulness. The owners should be added in the original histogram description. -If you are using a metric heavily and understand it intimately, feel free to -add yourself as an owner. @chromium.org email addresses are preferred. +Histograms need to have owners, who are the current experts on the metric. The +owners are the contact points for any questions or maintenance tasks. It's a +best practice to list multiple owners, so that there's no single point of +failure for such communication. +Being an owner means you are responsible for answering questions about the +metric, handling the maintenance if there are functional changes, and +deprecating the metric if it outlives its usefulness. If you are using a metric +heavily and understand it intimately, feel free to add yourself as an owner. +@chromium.org email addresses are preferred. + +If an appropriate mailing list is available, it's a good idea to include the +mailing list as a secondary owner. However, it's always a best practice to list +an individual as the primary owner. Listing an individual owner makes it clearer +who is ultimately most responsible for maintaining the metric, which makes it +less likely that such maintenance tasks will slip through the cracks. + +Notably, owners are asked to evaluate whether histograms have outlived their +usefulness. When a histogram is nearing expiry, a robot will file a reminder bug +in Monorail. It's important that somebody familiar with the histogram notices +and triages such bugs! ### Deleting Histogram Entries
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e4048c91..d990102 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -377,6 +377,188 @@ <int value="157" label="UMA_API_UNSELECT_ROW">unselectRow</int> </enum> +<enum name="AccessibilityWinAPIGetPropertyValueEnum"> +<!-- Property IDs are defined in UIAutomationClient.h in the Windows SDK. +Unknown properties are collapsed to zero. --> + + <int value="0" label="UNKNOWN"/> + <int value="30000" label="RuntimeId"/> + <int value="30001" label="BoundingRectangle"/> + <int value="30002" label="ProcessId"/> + <int value="30003" label="ControlType"/> + <int value="30004" label="LocalizedControlType"/> + <int value="30005" label="Name"/> + <int value="30006" label="AcceleratorKey"/> + <int value="30007" label="AccessKey"/> + <int value="30008" label="HasKeyboardFocus"/> + <int value="30009" label="IsKeyboardFocusable"/> + <int value="30010" label="IsEnabled"/> + <int value="30011" label="AutomationId"/> + <int value="30012" label="ClassName"/> + <int value="30013" label="HelpText"/> + <int value="30014" label="ClickablePoint"/> + <int value="30015" label="Culture"/> + <int value="30016" label="IsControlElement"/> + <int value="30017" label="IsContentElement"/> + <int value="30018" label="LabeledBy"/> + <int value="30019" label="IsPassword"/> + <int value="30020" label="NativeWindowHandle"/> + <int value="30021" label="ItemType"/> + <int value="30022" label="IsOffscreen"/> + <int value="30023" label="Orientation"/> + <int value="30024" label="FrameworkId"/> + <int value="30025" label="IsRequiredForForm"/> + <int value="30026" label="ItemStatus"/> + <int value="30027" label="IsDockPatternAvailable"/> + <int value="30028" label="IsExpandCollapsePatternAvailable"/> + <int value="30029" label="IsGridItemPatternAvailable"/> + <int value="30030" label="IsGridPatternAvailable"/> + <int value="30031" label="IsInvokePatternAvailable"/> + <int value="30032" label="IsMultipleViewPatternAvailable"/> + <int value="30033" label="IsRangeValuePatternAvailable"/> + <int value="30034" label="IsScrollPatternAvailable"/> + <int value="30035" label="IsScrollItemPatternAvailable"/> + <int value="30036" label="IsSelectionItemPatternAvailable"/> + <int value="30037" label="IsSelectionPatternAvailable"/> + <int value="30038" label="IsTablePatternAvailable"/> + <int value="30039" label="IsTableItemPatternAvailable"/> + <int value="30040" label="IsTextPatternAvailable"/> + <int value="30041" label="IsTogglePatternAvailable"/> + <int value="30042" label="IsTransformPatternAvailable"/> + <int value="30043" label="IsValuePatternAvailable"/> + <int value="30044" label="IsWindowPatternAvailable"/> + <int value="30045" label="ValueValue"/> + <int value="30046" label="ValueIsReadOnly"/> + <int value="30047" label="RangeValueValue"/> + <int value="30048" label="RangeValueIsReadOnly"/> + <int value="30049" label="RangeValueMinimum"/> + <int value="30050" label="RangeValueMaximum"/> + <int value="30051" label="RangeValueLargeChange"/> + <int value="30052" label="RangeValueSmallChange"/> + <int value="30053" label="ScrollHorizontalScrollPercent"/> + <int value="30054" label="ScrollHorizontalViewSize"/> + <int value="30055" label="ScrollVerticalScrollPercent"/> + <int value="30056" label="ScrollVerticalViewSize"/> + <int value="30057" label="ScrollHorizontallyScrollable"/> + <int value="30058" label="ScrollVerticallyScrollable"/> + <int value="30059" label="SelectionSelection"/> + <int value="30060" label="SelectionCanSelectMultiple"/> + <int value="30061" label="SelectionIsSelectionRequired"/> + <int value="30062" label="GridRowCount"/> + <int value="30063" label="GridColumnCount"/> + <int value="30064" label="GridItemRow"/> + <int value="30065" label="GridItemColumn"/> + <int value="30066" label="GridItemRowSpan"/> + <int value="30067" label="GridItemColumnSpan"/> + <int value="30068" label="GridItemContainingGrid"/> + <int value="30069" label="DockDockPosition"/> + <int value="30070" label="ExpandCollapseExpandCollapseState"/> + <int value="30071" label="MultipleViewCurrentView"/> + <int value="30072" label="MultipleViewSupportedViews"/> + <int value="30073" label="WindowCanMaximize"/> + <int value="30074" label="WindowCanMinimize"/> + <int value="30075" label="WindowWindowVisualState"/> + <int value="30076" label="WindowWindowInteractionState"/> + <int value="30077" label="WindowIsModal"/> + <int value="30078" label="WindowIsTopmost"/> + <int value="30079" label="SelectionItemIsSelected"/> + <int value="30080" label="SelectionItemSelectionContainer"/> + <int value="30081" label="TableRowHeaders"/> + <int value="30082" label="TableColumnHeaders"/> + <int value="30083" label="TableRowOrColumnMajor"/> + <int value="30084" label="TableItemRowHeaderItems"/> + <int value="30085" label="TableItemColumnHeaderItems"/> + <int value="30086" label="ToggleToggleState"/> + <int value="30087" label="TransformCanMove"/> + <int value="30088" label="TransformCanResize"/> + <int value="30089" label="TransformCanRotate"/> + <int value="30090" label="IsLegacyIAccessiblePatternAvailable"/> + <int value="30091" label="LegacyIAccessibleChildId"/> + <int value="30092" label="LegacyIAccessibleName"/> + <int value="30093" label="LegacyIAccessibleValue"/> + <int value="30094" label="LegacyIAccessibleDescription"/> + <int value="30095" label="LegacyIAccessibleRole"/> + <int value="30096" label="LegacyIAccessibleState"/> + <int value="30097" label="LegacyIAccessibleHelp"/> + <int value="30098" label="LegacyIAccessibleKeyboardShortcut"/> + <int value="30099" label="LegacyIAccessibleSelection"/> + <int value="30100" label="LegacyIAccessibleDefaultAction"/> + <int value="30101" label="AriaRole"/> + <int value="30102" label="AriaProperties"/> + <int value="30103" label="IsDataValidForForm"/> + <int value="30104" label="ControllerFor"/> + <int value="30105" label="DescribedBy"/> + <int value="30106" label="FlowsTo"/> + <int value="30107" label="ProviderDescription"/> + <int value="30108" label="IsItemContainerPatternAvailable"/> + <int value="30109" label="IsVirtualizedItemPatternAvailable"/> + <int value="30110" label="IsSynchronizedInputPatternAvailable"/> + <int value="30111" label="OptimizeForVisualContent"/> + <int value="30112" label="IsObjectModelPatternAvailable"/> + <int value="30113" label="AnnotationAnnotationTypeId"/> + <int value="30114" label="AnnotationAnnotationTypeName"/> + <int value="30115" label="AnnotationAuthor"/> + <int value="30116" label="AnnotationDateTime"/> + <int value="30117" label="AnnotationTarget"/> + <int value="30118" label="IsAnnotationPatternAvailable"/> + <int value="30119" label="IsTextPattern2Available"/> + <int value="30120" label="StylesStyleId"/> + <int value="30121" label="StylesStyleName"/> + <int value="30122" label="StylesFillColor"/> + <int value="30123" label="StylesFillPatternStyle"/> + <int value="30124" label="StylesShape"/> + <int value="30125" label="StylesFillPatternColor"/> + <int value="30126" label="StylesExtendedProperties"/> + <int value="30127" label="IsStylesPatternAvailable"/> + <int value="30128" label="IsSpreadsheetPatternAvailable"/> + <int value="30129" label="SpreadsheetItemFormula"/> + <int value="30130" label="SpreadsheetItemAnnotationObjects"/> + <int value="30131" label="SpreadsheetItemAnnotationTypes"/> + <int value="30132" label="IsSpreadsheetItemPatternAvailable"/> + <int value="30133" label="Transform2CanZoom"/> + <int value="30134" label="IsTransformPattern2Available"/> + <int value="30135" label="LiveSetting"/> + <int value="30136" label="IsTextChildPatternAvailable"/> + <int value="30137" label="IsDragPatternAvailable"/> + <int value="30138" label="DragIsGrabbed"/> + <int value="30139" label="DragDropEffect"/> + <int value="30140" label="DragDropEffects"/> + <int value="30141" label="IsDropTargetPatternAvailable"/> + <int value="30142" label="DropTargetDropTargetEffect"/> + <int value="30143" label="DropTargetDropTargetEffects"/> + <int value="30144" label="DragGrabbedItems"/> + <int value="30145" label="Transform2ZoomLevel"/> + <int value="30146" label="Transform2ZoomMinimum"/> + <int value="30147" label="Transform2ZoomMaximum"/> + <int value="30148" label="FlowsFrom"/> + <int value="30149" label="IsTextEditPatternAvailable"/> + <int value="30150" label="IsPeripheral"/> + <int value="30151" label="IsCustomNavigationPatternAvailable"/> + <int value="30152" label="PositionInSet"/> + <int value="30153" label="SizeOfSet"/> + <int value="30154" label="Level"/> + <int value="30155" label="AnnotationTypes"/> + <int value="30156" label="AnnotationObjects"/> + <int value="30157" label="LandmarkType"/> + <int value="30158" label="LocalizedLandmarkType"/> + <int value="30159" label="FullDescription"/> + <int value="30160" label="FillColor"/> + <int value="30161" label="OutlineColor"/> + <int value="30162" label="FillType"/> + <int value="30163" label="VisualEffects"/> + <int value="30164" label="OutlineThickness"/> + <int value="30165" label="CenterPoint"/> + <int value="30166" label="Rotation"/> + <int value="30167" label="Size"/> + <int value="30168" label="IsSelectionPattern2Available"/> + <int value="30169" label="Selection2FirstSelectedItem"/> + <int value="30170" label="Selection2LastSelectedItem"/> + <int value="30171" label="Selection2CurrentSelectedItem"/> + <int value="30172" label="Selection2ItemCount"/> + <int value="30173" label="HeadingLevel"/> + <int value="30174" label="IsDialog"/> +</enum> + <enum name="AccessoryAction"> <int value="0" label="Automatic password generation"/> <int value="1" label="'Manage all passwords' link"/> @@ -2817,6 +2999,7 @@ <int value="12" label="User requested to provide cardholder name"/> <int value="13" label="Max strikes, did not show infobar (mobile only)"/> <int value="14" label="User requested to provide expiration date"/> + <int value="15" label="Card was not in a supported bin range"/> </enum> <enum name="AutofillCreditCardInfoBar"> @@ -12185,6 +12368,187 @@ is ARC app(Android app in ChromeOS)"/> </enum> +<enum name="DownEventInputFormFactorDestinationCombination2"> + <int value="0" + label="Unknown input in clamshell mode, destination is + others(everything except browser and apps)"/> + <int value="1" + label="Unknown input in touchview mode landscape orientation, + destination is others(everything except browser and apps)"/> + <int value="2" + label="Unknown input in touchview mode portrait orientation, + destination is others(everything except browser and apps)"/> + <int value="3" + label="Mouse input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="4" + label="Mouse input in touchview mode landscape orientation, destination + is others(everything except browser and apps)"/> + <int value="5" + label="Mouse input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="6" + label="Stylus input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="7" + label="Stylus input in touchview mode landscape orientation, + destination is others(everything except browser and apps)"/> + <int value="8" + label="Stylus input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="9" + label="Touch input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="10" + label="Touch input in touchview mode landscape orientation, destination + is others(everything except browser and apps)"/> + <int value="11" + label="Touch input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="12" + label="Unknown input in clamshell mode, destination is inside the + browser frame"/> + <int value="13" + label="Unknown input in touchview mode landscape orientation, + destination is inside the browser frame"/> + <int value="14" + label="Unknown input in touchview mode portrait orientation, + destination is inside the browser frame"/> + <int value="15" + label="Mouse input in clamshell mode, destination is inside the browser + frame"/> + <int value="16" + label="Mouse input in touchview mode landscape orientation, destination + is inside the browser frame"/> + <int value="17" + label="Mouse input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="18" + label="Stylus input in clamshell mode, destination is inside the + browser frame"/> + <int value="19" + label="Stylus input in touchview mode landscape orientation, + destination is inside the browser frame"/> + <int value="20" + label="Stylus input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="21" + label="Touch input in clamshell mode, destination is inside the browser + frame"/> + <int value="22" + label="Touch input in touchview mode landscape orientation, destination + is inside the browser frame"/> + <int value="23" + label="Touch input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="24" + label="Unknown input in clamshell mode, destination is regular chrome + app"/> + <int value="25" + label="Unknown input in touchview mode landscape orientation, + destination is regular chrome app"/> + <int value="26" + label="Unknown input in touchview mode portrait orientation, + destination is regular chrome app"/> + <int value="27" + label="Mouse input in clamshell mode, destination is regular chrome app"/> + <int value="28" + label="Mouse input in touchview mode landscape orientation, destination + is regular chrome app"/> + <int value="29" + label="Mouse input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="30" + label="Stylus input in clamshell mode, destination is regular chrome + app"/> + <int value="31" + label="Stylus input in touchview mode landscape orientation, + destination is regular chrome app"/> + <int value="32" + label="Stylus input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="33" + label="Touch input in clamshell mode, destination is regular chrome app"/> + <int value="34" + label="Touch input in touchview mode landscape orientation, destination + is regular chrome app"/> + <int value="35" + label="Touch input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="36" + label="Unknown input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="37" + label="Unknown input in touchview mode landscape orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="38" + label="Unknown input in touchview mode portrait orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="39" + label="Mouse input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="40" + label="Mouse input in touchview mode landscape orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="41" + label="Mouse input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="42" + label="Stylus input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="43" + label="Stylus input in touchview mode landscape orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="44" + label="Stylus input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="45" + label="Touch input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="46" + label="Touch input in touchview mode landscape orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="47" + label="Touch input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="48" + label="Unknown input in clamshell mode, destination is Crostini + app(Linux app in ChromeOS)"/> + <int value="49" + label="Unknown input in touchview mode landscape orientation, + destination is Crostini app(Linux app in ChromeOS)"/> + <int value="50" + label="Unknown input in touchview mode portrait orientation, + destination is Crostini app(Linux app in ChromeOS)"/> + <int value="51" + label="Mouse input in clamshell mode, destination is Crostini app(Linux + app in ChromeOS)"/> + <int value="52" + label="Mouse input in touchview mode landscape orientation, destination + is Crostini app(Linux app in ChromeOS)"/> + <int value="53" + label="Mouse input in touchview mode portrait orientation, destination + is Crostini app(Linux app in ChromeOS)"/> + <int value="54" + label="Stylus input in clamshell mode, destination is Crostini + app(Linux app in ChromeOS)"/> + <int value="55" + label="Stylus input in touchview mode landscape orientation, + destination is Crostini app(Linux app in ChromeOS)"/> + <int value="56" + label="Stylus input in touchview mode portrait orientation, destination + is Crostini app(Linux app in ChromeOS)"/> + <int value="57" + label="Touch input in clamshell mode, destination is Crostini app(Linux + app in ChromeOS)"/> + <int value="58" + label="Touch input in touchview mode landscape orientation, destination + is Crostini app(Linux app in ChromeOS)"/> + <int value="59" + label="Touch input in touchview mode portrait orientation, destination + is Crostini app(Linux app in ChromeOS)"/> +</enum> + <enum name="DownEventSource"> <int value="0" label="Unknown"/> <int value="1" label="Mouse"/> @@ -12959,6 +13323,7 @@ <int value="353" label="potm"/> <int value="354" label="ppsm"/> <int value="355" label="pps"/> + <int value="356" label="mobileconfig"/> </enum> <enum name="DownloadItem.DangerType"> @@ -21794,6 +22159,8 @@ <int value="2823" label="CSSValueAppearanceTextFieldForTemporalRendered"/> <int value="2824" label="BuiltInModuleKvStorage"/> <int value="2825" label="BuiltInModuleVirtualScroller"/> + <int value="2826" label="AdClickNavigation"/> + <int value="2827" label="RTCStatsRelativePacketArrivalDelay"/> </enum> <enum name="FeaturePolicyFeature"> @@ -21869,6 +22236,30 @@ <int value="2" label="Fetch failure"/> </enum> +<enum name="FeedInternalError"> + <int value="0" label="SWITCH_TO_EPHEMERAL"/> + <int value="1" label="NO_URL_FOR_OPEN"/> + <int value="2" label="FAILED_TO_RESTORE"/> + <int value="3" label="NO_ROOT_FEATURE"/> + <int value="4" label="TOP_LEVEL_UNBOUND_CHILD"/> + <int value="5" label="TOP_LEVEL_INVALID_FEATURE_TYPE"/> + <int value="6" label="CLUSTER_CHILD_MISSING_FEATURE"/> + <int value="7" label="CLUSTER_CHILD_NOT_CARD"/> + <int value="8" label="CARD_CHILD_MISSING_FEATURE"/> + <int value="9" label="NULL_SHARED_STATES"/> +</enum> + +<enum name="FeedRequestReason"> + <int value="0" label="UNKNOWN"/> + <int value="1" label="ZERO_STATE"/> + <int value="2" label="HOST_REQUESTED"/> + <int value="3" label="OPEN_WITH_CONTENT"/> + <int value="4" label="MANUAL_CONTINUATION"/> + <int value="5" label="AUTOMATIC_CONTINUATION"/> + <int value="6" label="OPEN_WITHOUT_CONTENT"/> + <int value="7" label="CLEAR_ALL"/> +</enum> + <enum name="FeedSchedulerRefreshStatus"> <int value="0" label="Should refresh"/> <int value="1" label="Outstanding request"/> @@ -21889,6 +22280,12 @@ <int value="5" label="Infinite feed"/> </enum> +<enum name="FeedZeroStateShowReason"> + <int value="0" label="ERROR"/> + <int value="1" label="NO_CONTENT"/> + <int value="2" label="CONTENT_DISMISSED"/> +</enum> + <enum name="FetchRequestMode"> <int value="0" label="SameOrigin"/> <int value="1" label="NoCORS"/> @@ -27844,6 +28241,26 @@ <int value="4" label="Script"/> </enum> +<enum name="InlineUpdateCallFailure"> + <int value="0" label="StartUpdate Failed"/> + <int value="1" label="StartUpdate Exception"/> + <int value="2" label="CompleteUpdate Failed"/> + <int value="3" label="GetUpdateStatus Failed"/> +</enum> + +<enum name="InlineUpdateErrorCodes"> + <int value="0" label="No Error"/> + <int value="1" label="No Error (Partially Allowed)"/> + <int value="2" label="Error - Unknown"/> + <int value="3" label="Error - API Not Available"/> + <int value="4" label="Error - Invalid Request"/> + <int value="5" label="Error - Install Unavailable"/> + <int value="6" label="Error - Install Not Allowed"/> + <int value="7" label="Error - Download Not Present"/> + <int value="8" label="Error - Internal Error"/> + <int value="9" label="Error - Untracked (Not Known to UMA)"/> +</enum> + <enum name="InputMethodCategory"> <int value="0" label="Unkown"/> <int value="1" label="XKB">XKeyboard</int> @@ -31478,6 +31895,7 @@ <int value="-1335017208" label="KeyboardLockAPI:enabled"/> <int value="-1334327410" label="ash-enable-touch-view-testing"/> <int value="-1332267458" label="RemoveNavigationHistory:enabled"/> + <int value="-1331831950" label="site-isolation-for-password-sites:enabled"/> <int value="-1327676774" label="disable-accelerated-mjpeg-decode"/> <int value="-1326463296" label="SSLCommittedInterstitials:disabled"/> <int value="-1325887476" label="NewPrintPreview:enabled"/> @@ -32051,6 +32469,8 @@ <int value="-366949535" label="KeyboardShortcutViewerApp:enabled"/> <int value="-365920680" label="ImageCaptureAPI:disabled"/> <int value="-365806433" label="BuiltInModuleAll:disabled"/> + <int value="-364604989" + label="LinkManagedNoticeToChromeUIManagementURL:disabled"/> <int value="-364587218" label="ResourceLoadScheduler:enabled"/> <int value="-364325011" label="enable-files-quick-view"/> <int value="-364267715" label="disable-native-cups"/> @@ -32308,6 +32728,7 @@ <int value="54571864" label="EnableDisplayZoomSetting:enabled"/> <int value="56723110" label="enable-webfonts-intervention"/> <int value="56900498" label="OmniboxOneClickUnelide:enabled"/> + <int value="57255632" label="site-isolation-for-password-sites:disabled"/> <int value="57555893" label="NewContactsPicker:disabled"/> <int value="57639188" label="SoundContentSetting:disabled"/> <int value="57791920" label="MemoryCoordinator:enabled"/> @@ -32470,6 +32891,7 @@ <int value="359601954" label="CrostiniUsbSupport:enabled"/> <int value="360391863" label="NTPOfflineBadge:enabled"/> <int value="360599302" label="enable-gpu-rasterization"/> + <int value="362644448" label="memlog-in-process"/> <int value="365467768" label="prefetch-search-results"/> <int value="367063319" label="PasswordImport:disabled"/> <int value="368854020" label="ash-screen-rotation-animation"/> @@ -32578,6 +33000,8 @@ <int value="549483647" label="EnableUnifiedMultiDeviceSettings:disabled"/> <int value="550378029" label="reset-app-list-install-state"/> <int value="550387510" label="NTPAssetDownloadSuggestions:disabled"/> + <int value="556555487" + label="AutofillDoNotUploadSaveUnsupportedCards:disabled"/> <int value="557200974" label="WebSocketHandshakeReuseConnection:disabled"/> <int value="557915559" label="CCTModuleCustomRequestHeader:enabled"/> <int value="558873715" label="SiteDetails:disabled"/> @@ -33070,6 +33494,8 @@ <int value="1346994602" label="SyncPseudoUSSDictionary:enabled"/> <int value="1351830811" label="do-not-ignore-autocomplete-off"/> <int value="1352447982" label="enable-lcd-text"/> + <int value="1353066950" + label="AutofillDoNotUploadSaveUnsupportedCards:enabled"/> <int value="1353629763" label="MediaSessionAccelerators:enabled"/> <int value="1355923367" label="CrOSContainer:disabled"/> <int value="1359972809" label="enable-gesture-deletion"/> @@ -33463,6 +33889,8 @@ <int value="1988810119" label="AutofillDropdownLayout:enabled"/> <int value="1989051182" label="view-passwords:enabled"/> <int value="1989877708" label="PostScriptPrinting:enabled"/> + <int value="1990562608" + label="LinkManagedNoticeToChromeUIManagementURL:enabled"/> <int value="1991771852" label="LeftToRightUrls:enabled"/> <int value="1991912338" label="ModuleScriptsDynamicImport:enabled"/> <int value="1992466116" label="enable-passive-event-listeners-due-to-fling"/> @@ -33486,6 +33914,7 @@ <int value="2005614493" label="tab-management-experiment-type-dill"/> <int value="2006413281" label="ContextualSuggestionsAlternateCardLayout:enabled"/> + <int value="2009097351" label="memlog-sampling-rate"/> <int value="2009362691" label="AllowStartingServiceManagerOnly:enabled"/> <int value="2014331873" label="NTPDownloadSuggestions:disabled"/> <int value="2014629801" label="view-passwords:disabled"/> @@ -33548,7 +33977,6 @@ <int value="2123567684" label="OptimizeLoadingIPCForSmallResources:enabled"/> <int value="2126203058" label="force-show-update-menu-badge"/> <int value="2129184006" label="NTPOfflinePageDownloadSuggestions:enabled"/> - <int value="2129251171" label="memlog-sampling"/> <int value="2129929643" label="enable-use-zoom-for-dsf"/> <int value="2134480727" label="MediaSessionAccelerators:disabled"/> <int value="2135408204" label="OverscrollHistoryNavigation:disabled"/> @@ -47637,6 +48065,7 @@ <int value="353" label="POTM"/> <int value="354" label="PPSM"/> <int value="355" label="PPS"/> + <int value="356" label="MOBILECONFIG"/> </enum> <enum name="SBClientDownloadIsSignedBinary"> @@ -53940,6 +54369,11 @@ <int value="2" label="Forced Full"/> </enum> +<enum name="UpdateInteractionSource"> + <int value="0" label="From Menu"/> + <int value="1" label="From Infobar"/> +</enum> + <enum name="UpdatePasswordSubmissionEvent"> <int value="0" label="NO_ACCOUNTS_CLICKED_UPDATE"/> <int value="1" label="NO_ACCOUNTS_CLICKED_NOPE"/> @@ -53962,6 +54396,16 @@ <int value="3" label="AUTO_UPDATES_ONLY"/> </enum> +<enum name="UpdateState"> + <int value="0" label="None"/> + <int value="1" label="Update Available"/> + <int value="2" label="Unsupported OS Version"/> + <int value="3" label="Inline Update Available"/> + <int value="4" label="Inline Update Downloading"/> + <int value="5" label="Inline Update Ready"/> + <int value="6" label="Inline Update Failed"/> +</enum> + <enum name="UpgradeDetectorRollbackReason"> <int value="0" label="Channel switch to more stable channel"/> <int value="1" label="Admin-initiated enterprise rollback"/> @@ -55927,6 +56371,13 @@ <int value="4" label="Abandoned"/> </enum> +<enum name="WebAuthenticationRelyingPartySecurityCheckFailure"> + <int value="0" label="Opaque or Non-Secure Origin"/> + <int value="1" label="Relying Party Id Invalid"/> + <int value="2" label="AppId Extension Invalid"/> + <int value="3" label="AppId Extension Domain Mismatch"/> +</enum> + <enum name="WebAuthenticationU2FAttestationPromptResult"> <int value="0" label="Queried"/> <int value="1" label="Allowed"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 05ea8200..522cea84 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -539,6 +539,16 @@ <summary>Tracks usage of all public Windows accessibility APIs.</summary> </histogram> +<histogram name="Accessibility.WinAPIs.GetPropertyValue" + enum="AccessibilityWinAPIGetPropertyValueEnum" expires_after="2019-09-07"> + <owner>dmazzoni@chromium.org</owner> + <owner>nektar@chromium.org</owner> + <owner>kbabbitt@microsoft.com</owner> + <summary> + Tracks properties requested via UI Automation GetPropertyValue(). + </summary> +</histogram> + <histogram name="Accessibility.WinAudioDescription" enum="BooleanEnabled" expires_after="2019-11-02"> <owner>dmazzoni@chromium.org</owner> @@ -3900,6 +3910,16 @@ </summary> </histogram> +<histogram name="Apps.AppListResultClickIndexAndQueryLength"> + <owner>tby@chromium.org</owner> + <owner>jiameng@chromium.org</owner> + <summary> + The index of a clicked result in the search result box and the length of the + search query. The index is relative to the SearchResultListView, not the + overall position in the suggestion window. + </summary> +</histogram> + <histogram name="Apps.AppListSearchBoxActivated" enum="SearchBoxActivationSource"> <owner>newcomer@chromium.org</owner> @@ -4033,6 +4053,16 @@ </summary> </histogram> +<histogram name="Apps.AppListTileClickIndexAndQueryLength"> + <owner>tby@chromium.org</owner> + <owner>jiameng@chromium.org</owner> + <summary> + The index of a clicked result in the search result app tiles and the length + of the search query. The index is relative to the SearchTileItemListView, + not the overall position in the suggestion window. + </summary> +</histogram> + <histogram name="Apps.AppListTimeToDiscover" units="ms"> <owner>tapted@chromium.org</owner> <summary> @@ -4947,10 +4977,9 @@ </histogram> <histogram name="Arc.Supervision.Transition.Result" - enum="ArcSupervisionTransitionResult" expires_after="M74"> + enum="ArcSupervisionTransitionResult" expires_after="M76"> <owner>menegola@google.com</owner> <owner>escordeiro@google.com</owner> - <owner>brunokim@google.com</owner> <owner>unichromeos-eng@google.com</owner> <summary> The result (success or the type of failure) of ARC supervision transition @@ -17818,6 +17847,13 @@ </summary> </histogram> +<histogram name="ContentSuggestions.Feed.InternalError" + units="FeedInternalError" expires_after="2020-02-22"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary>The Feed library encountered an error at any time.</summary> +</histogram> + <histogram name="ContentSuggestions.Feed.LoadKeysSuccess" enum="BooleanSuccess" expires_after="2019-10-01"> <owner>gangwu@chromium.org</owner> @@ -18078,6 +18114,46 @@ </summary> </histogram> +<histogram name="ContentSuggestions.Feed.ServerRequest.Reason" + enum="FeedRequestReason" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + The reason for a server request from the Feed's prespective, when the + request is started. + </summary> +</histogram> + +<histogram name="ContentSuggestions.Feed.TokenCompleted.ContentCount" + units="count" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + How many top level features were in the continuation response, typically + clusters. Recorded when the fetch completes successfully. + </summary> +</histogram> + +<histogram name="ContentSuggestions.Feed.TokenCompleted.TokenCount" + units="count" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + How many tokens were in the continuation response, typically ways to fetch + more articles. Recorded when the fetch completes successfully. + </summary> +</histogram> + +<histogram name="ContentSuggestions.Feed.TokenFailedToCompleted" units="count" + expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + When a token fails to complete, how many failures this token has seen. + Record when the fetch fails. + </summary> +</histogram> + <histogram name="ContentSuggestions.Feed.TokenFetchStatus" enum="GoogleServiceAuthError"> <obsolete> @@ -18086,10 +18162,40 @@ <owner>pnoland@chromium.org</owner> <summary> Android: failure reason when attempting to fetch an OAuth token for the - feed. Recorded when a token fetch completes. + feed. Recorded when an artcile fetch completes. </summary> </histogram> +<histogram + name="ContentSuggestions.Feed.ZeroStateRefreshCompleted.ContentCount" + units="count" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + How many top level features were in an initial article fetch, typically + clusters. Recorded when an article fetch completes and were previously in + zero state. + </summary> +</histogram> + +<histogram name="ContentSuggestions.Feed.ZeroStateRefreshCompleted.TokenCount" + units="count" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary> + How many tokens were in an initial article fetch, typically ways to fetch + more articles. Recorded when an article fetch completes and were previously + in zero state. + </summary> +</histogram> + +<histogram name="ContentSuggestions.Feed.ZeroStateShown.Reason" + enum="FeedZeroStateShowReason" expires_after="2020-02-25"> + <owner>skym@chromium.org</owner> + <owner>gangwu@chromium.org</owner> + <summary>The reason the zero state (no articles) is shown to a user.</summary> +</histogram> + <histogram name="ContentSuggestions.FetchPendingPlaceholder.VisibleDuration" units="ms"> <obsolete> @@ -20491,6 +20597,17 @@ </summary> </histogram> +<histogram name="DataReductionProxy.ConfigService.ConnectionSetupTime" + units="ms" expires_after="2019-12-31"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + The time delta between connectStart and connectEnd of the client config + request. This is recorded only on successful requests when connectStart and + connectEnd were non-null. + </summary> +</histogram> + <histogram name="DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess"> <owner>bengr@chromium.org</owner> @@ -20523,6 +20640,16 @@ </summary> </histogram> +<histogram name="DataReductionProxy.ConfigService.HttpRequestRTT" units="ms" + expires_after="2019-12-31"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + The time delta between requestStart and requestEnd of the client config + request. This is recorded only on successful requests. + </summary> +</histogram> + <histogram name="DataReductionProxy.ConfigService.HTTPRequests" enum="DataReductionProxyConfigServiceHTTPRequests"> <owner>bengr@chromium.org</owner> @@ -29111,16 +29238,36 @@ </histogram> <histogram name="Event.DownEventCount.PerInputFormFactorDestinationCombination" - enum="DownEventInputFormFactorDestinationCombination"> + enum="DownEventInputFormFactorDestinationCombination" expires_after="M76"> <owner>tbuckley@chromium.org</owner> <summary> + Deprecated 02/2019 in favor of + Event.DownEventCount.PerInputFormFactorDestinationCombination2. + The number of down events received per input, form factor, and destination combination. Input is down events generated by mouse/touch/stylus. Form factor is down events generated by clamshell/touchviewLandscape/touchviewPortrait. Destination: Every down event that is targeted to each destination will be - counted,including those that don't have an effect. For example: Tapping on a + counted including those that don't have an effect. For example: Tapping on a + disabled button inside the browser frame will be treated as down events on + browser window. + </summary> +</histogram> + +<histogram + name="Event.DownEventCount.PerInputFormFactorDestinationCombination2" + enum="DownEventInputFormFactorDestinationCombination2" expires_after="M76"> + <owner>tbuckley@chromium.org</owner> + <summary> + The number of down events received per destination, input and form factor + combination. + + Input is down events generated by mouse/touch/stylus. Form factor is down + events generated by clamshell/touchviewLandscape/touchviewPortrait. + Destination: Every down event that is targeted to each destination will be + counted including those that don't have an effect. For example: Tapping on a disabled button inside the browser frame will be treated as down events on browser window. </summary> @@ -37703,6 +37850,16 @@ </summary> </histogram> +<histogram name="FileBrowser.Recent.LoadCrostini" units="ms" + expires_after="M79"> + <owner>slangley@chromium.org</owner> + <owner>weifangsun@chromium.org</owner> + <summary> + Time to load a recently modified file list from Crostini. It is triggered + when the user opens or reloads Recent view in the Files app. + </summary> +</histogram> + <histogram name="FileBrowser.Recent.LoadDownloads" units="ms" expires_after="M79"> <owner>slangley@chromium.org</owner> @@ -39323,6 +39480,56 @@ </summary> </histogram> +<histogram name="GoogleUpdate.Inline.CallFailure" + enum="InlineUpdateCallFailure" expires_after="2019-10-30"> + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) Records the instances where Play update API calls failed. + </summary> +</histogram> + +<histogram name="GoogleUpdate.Inline.StateChange.Error" + enum="InlineUpdateErrorCodes" expires_after="2019-10-30"> +<!-- Name completed by histogram_suffixes name="GoogleUpdate.Inline.InstallStatus" --> + + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) Records the instances where Play update API notified us of an + install error during an update. This is keyed on the specific state so we + can tell which states are seeing which errors. + </summary> +</histogram> + +<histogram name="GoogleUpdate.Inline.UI.Install.Source" + enum="UpdateInteractionSource" expires_after="2019-10-30"> + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) The UI component that triggered an inline update to finish + and install. + </summary> +</histogram> + +<histogram name="GoogleUpdate.Inline.UI.Retry.Source" + enum="UpdateInteractionSource" expires_after="2019-10-30"> + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) The UI component that triggered an inline update to retry. + </summary> +</histogram> + +<histogram name="GoogleUpdate.Inline.UI.Start.Source" + enum="UpdateInteractionSource" expires_after="2019-10-30"> + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) The UI component that triggered an inline update to start. + </summary> +</histogram> + <histogram name="GoogleUpdate.InstallerExitCode" enum="InstallStatus"> <owner>grt@chromium.org</owner> <summary> @@ -39352,6 +39559,16 @@ </summary> </histogram> +<histogram name="GoogleUpdate.StartUp.State" enum="UpdateState" + expires_after="2019-10-30"> + <owner>dtrainor@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary> + (Android-only) The state of any in-progress updates when the process first + starts and queries for it. + </summary> +</histogram> + <histogram name="GoogleUpdate.UnexpectedState"> <owner>grt@chromium.org</owner> <summary> @@ -51857,6 +52074,18 @@ </summary> </histogram> +<histogram name="Media.WebMediaPlayerImpl.HLS.HasAccessControl" enum="Boolean" + expires_after="2019-12-31"> + <owner>sandersd@chromium.org</owner> + <owner>tguilbert@chromium.org</owner> + <summary> + When an HLS manifest is found during loading (on Android only), and the + response is CORS cross-origin, this histogram records whether the response + included an Access-Control-Allow-Origin header. Such requests are likely to + be supported by fetch() if the mode is correctly configured. + </summary> +</histogram> + <histogram name="Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin" enum="Boolean" expires_after="2019-12-31"> <owner>sandersd@chromium.org</owner> @@ -51883,6 +52112,11 @@ <histogram name="Media.WebMediaPlayerImpl.HLS.WouldTaintOrigin" enum="Boolean" expires_after="2019-12-31"> + <obsolete> + Deprecated because an overwhelming majority of pages do not set the + crossorigin attribute and as a result most HLS content is counted. + Superseded by Media.WebMediaPlayerImpl.HLS.HasAccessControl. + </obsolete> <owner>sandersd@chromium.org</owner> <owner>tguilbert@chromium.org</owner> <summary> @@ -75952,6 +76186,9 @@ <histogram name="OfflinePages.SQLStorage.CreateDirectoryResult" enum="PlatformFileError"> + <obsolete> + Removed 3/2019. + </obsolete> <owner>dimich@chromium.org</owner> <summary> If the directory to store the SQLite database file does not exist, it is @@ -79743,6 +79980,21 @@ </histogram> <histogram + name="PageLoad.Experimental.PaintTiming.LargestContentPaint.AllFrames.ContentType" + enum="LargestContentType" expires_after="2019-04-23"> + <owner>maxlg@chromium.org</owner> + <owner>npm@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + Measures whether the largest content paint, whose timestamp is measured by + PageLoad.Experimental.PaintTiming.NavigationToLargestContentPaintAllFrames, + comes from text or image. This value is recorded whenever + PageLoad.Experimental.PaintTiming.NavigationToLargestContentPaintAllFrames + is recorded. + </summary> +</histogram> + +<histogram name="PageLoad.Experimental.PaintTiming.LargestContentPaint.ContentType" enum="LargestContentType" expires_after="2019-04-23"> <owner>maxlg@chromium.org</owner> @@ -79786,6 +80038,22 @@ </histogram> <histogram + name="PageLoad.Experimental.PaintTiming.NavigationToLargestContentPaintAllFrames" + units="ms" expires_after="2019-04-23"> + <owner>maxlg@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + Measures the time from navigation timing's navigation start to the time the + largest content (text or image) is first painted, for main frame documents. + Excludes any content painted after user input. The value is recorded at the + end of each page load unless there is an abort or user input before text or + image paint. Compared with NavigationToLargestContentPaint, this is the + aggregate results from all frames, while NavigationToLargestContentPaint is + only for main frame. See http://bit.ly/fcp_plus_plus for details. + </summary> +</histogram> + +<histogram name="PageLoad.Experimental.PaintTiming.NavigationToLargestImagePaint" units="ms" expires_after="2019-04-23"> <owner>maxlg@chromium.org</owner> @@ -86792,6 +87060,40 @@ </summary> </histogram> +<histogram name="Platform.ZramIncompressiblePages" units="pages" + expires_after="2020-03-06"> + <owner>asavery@chromium.org</owner> + <owner>gwendal@chromium.org</owner> + <summary> + Number of incompressible pages stored in zram. A large number suggests lower + compression effectiveness. Snapshot every 30s. + </summary> +</histogram> + +<histogram name="Platform.ZramIncompressibleRatioPercent.PostCompression" + units="%" expires_after="2020-03-06"> + <owner>asavery@chromium.org</owner> + <owner>gwendal@chromium.org</owner> + <summary> + The fraction of compressed memory that consists of incompressible pages. We + express this as a percentage (between 0% and 100%). Values close to 100% + mean we are not able to effectively benefit from compression. Snapshot every + 30s. + </summary> +</histogram> + +<histogram name="Platform.ZramIncompressibleRatioPercent.PreCompression" + units="%" expires_after="2020-03-06"> + <owner>asavery@chromium.org</owner> + <owner>gwendal@chromium.org</owner> + <summary> + The fraction of the uncompressed memory size that consists of incompressible + pages. We express this as a percentage (between 0% and 100%). Values close + to 100% mean we are not able to effectively benefit from compression. + Snapshot every 30s. + </summary> +</histogram> + <histogram name="Platform.ZramSavings" units="MB"> <owner>semenzato@google.com</owner> <summary> @@ -93190,8 +93492,10 @@ </summary> </histogram> -<histogram name="Quota.ErrorsOnEvictingOriginPerHour" - expires_after="2018-08-30"> +<histogram name="Quota.ErrorsOnEvictingOriginPerHour"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary> Number of errors on evicting origin by QuotaTemporaryStorageEvictor in an @@ -93199,8 +93503,10 @@ </summary> </histogram> -<histogram name="Quota.ErrorsOnGettingUsageAndQuotaPerHour" - expires_after="2018-08-30"> +<histogram name="Quota.ErrorsOnGettingUsageAndQuotaPerHour"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary> Number of errors on getting usage and quota by QuotaTemporaryStorageEvictor @@ -93296,38 +93602,50 @@ <summary>Number of evicted origins per round.</summary> </histogram> -<histogram name="Quota.NumberOfPersistentStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfPersistentStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of origins using persistent storage.</summary> </histogram> -<histogram name="Quota.NumberOfProtectedPersistentStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfProtectedPersistentStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of protected origins using persistent storage.</summary> </histogram> -<histogram name="Quota.NumberOfProtectedTemporaryStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfProtectedTemporaryStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of protected origins using temporary storage.</summary> </histogram> -<histogram name="Quota.NumberOfTemporaryStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfTemporaryStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of origins using temporary storage.</summary> </histogram> -<histogram name="Quota.NumberOfUnlimitedPersistentStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfUnlimitedPersistentStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of unlimited origins using persistent storage.</summary> </histogram> -<histogram name="Quota.NumberOfUnlimitedTemporaryStorageOrigins" - expires_after="2018-08-30"> +<histogram name="Quota.NumberOfUnlimitedTemporaryStorageOrigins"> + <obsolete> + Expired on 2018-08-30. Removed in M74. + </obsolete> <owner>tzik@chromium.org</owner> <summary>Number of unlimited origins using temporary storage.</summary> </histogram> @@ -93443,8 +93761,10 @@ </summary> </histogram> -<histogram name="Quota.UsageOverageOfTemporaryGlobalStorage" units="MB" - expires_after="2018-08-30"> +<histogram name="Quota.UsageOverageOfTemporaryGlobalStorage" units="MB"> + <obsolete> + Expired on 2018-08-30. Removed in M75. + </obsolete> <owner>tzik@chromium.org</owner> <summary> Overage of the temporary global storage usage at beginning of an eviction @@ -128260,6 +128580,40 @@ </summary> </histogram> +<histogram name="WebAuthentication.CredentialRequestAllowCredentialsCount" + units="credentials" expires_after="2019-12-31"> + <owner>kenrb@chromium.org</owner> + <owner>kpaulhamus@chromium.org</owner> + <summary> + When a relying party is attempting to authenticate a user using the + WebAuthentication API, this metric reports the number of valid credentials + that the RP has registered for the user. + </summary> +</histogram> + +<histogram name="WebAuthentication.MakeCredentialExcludeCredentialsCount" + units="credentials" expires_after="2019-12-31"> + <owner>kenrb@chromium.org</owner> + <summary> + When a relying party is attempting to register a credential for a new user + using the WebAuthentication API, this metric reports the number of existing + credentials already registered in order to prevent re-registration. + </summary> +</histogram> + +<histogram name="WebAuthentication.RelyingPartySecurityCheckFailure" + enum="WebAuthenticationRelyingPartySecurityCheckFailure" + expires_after="2019-12-31"> + <owner>kenrb@chromium.org</owner> + <summary> + Records failures associated with verifying the relying party origin when + that relying party is attempting to make a credential or get an assertion + using the WebAuthentication API. Failures include when the relying party's + origin is opaque or non-secure, or when the caller-provided relying party ID + or app ID is not valid for this origin. + </summary> +</histogram> + <histogram name="WebAuthentication.U2FAttestationPromptResult" enum="WebAuthenticationU2FAttestationPromptResult"> <owner>agl@chromium.org</owner> @@ -137796,6 +138150,18 @@ <affected-histogram name="Favicons.DownloadAttempts"/> </histogram_suffixes> +<histogram_suffixes name="FeedIsSynthetic" separator="." ordering="suffix"> + <suffix name="NotSynthetic" + label="Continuations that require making remote requests to fetch more + articles."/> + <suffix name="Synthetic" + label="Continuations generated by the Feed library."/> + <affected-histogram + name="ContentSuggestions.Feed.TokenCompleted.ContentCount"/> + <affected-histogram name="ContentSuggestions.Feed.TokenCompleted.TokenCount"/> + <affected-histogram name="ContentSuggestions.Feed.TokenFailedToCompleted"/> +</histogram_suffixes> + <histogram_suffixes name="FeedOrHostOlder" separator="."> <suffix name="FeedIsOlder"/> <suffix name="HostIsOlder"/> @@ -138106,6 +138472,20 @@ <affected-histogram name="GoogleSearch.AccessPoint"/> </histogram_suffixes> +<histogram_suffixes name="GoogleUpdate.Inline.InstallStatus" separator="."> + <suffix name="Canceled" label="Canceled"/> + <suffix name="Downloaded" label="Downloaded"/> + <suffix name="Downloading" label="Downloading"/> + <suffix name="Failed" label="Failed"/> + <suffix name="Installed" label="Installed"/> + <suffix name="Installing" label="Installing"/> + <suffix name="Pending" label="Pending"/> + <suffix name="RequiresUiIntent" label="Requires UI Intent"/> + <suffix name="Unknown" label="Unknown"/> + <suffix name="Untracked" label="Untracked Status (Not Known to UMA)"/> + <affected-histogram name="GoogleUpdate.Inline.StateChange.Error"/> +</histogram_suffixes> + <histogram_suffixes name="GPU.ContextType" separator="."> <suffix name="GLES" label="GLES Context."/> <suffix name="WebGL" label="WebGL Context."/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index d1e3be0..478d407 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -3825,6 +3825,17 @@ image) within viewport. See http://bit.ly/fcp_plus_plus for more details. </summary> </metric> + <metric + name="Experimental.PaintTiming.NavigationToLargestContentPaintAllFrames"> + <summary> + Measures the time in milliseconds from navigation timing's navigation + start to the time when the page first paints the largest content (text or + image) within viewport. Compared with NavigationToLargestContentPaint, + this is the aggregate results from all frames, while + NavigationToLargestContentPaint is only for main frame. See + http://bit.ly/fcp_plus_plus for more details. + </summary> + </metric> <metric name="Experimental.PaintTiming.NavigationToLargestImagePaint"> <summary> Measures the time in milliseconds from navigation timing's navigation
diff --git a/tools/perf/cli_tools/soundwave/commands.py b/tools/perf/cli_tools/soundwave/commands.py index 61e9cc7..b6f8522a 100644 --- a/tools/perf/cli_tools/soundwave/commands.py +++ b/tools/perf/cli_tools/soundwave/commands.py
@@ -4,7 +4,10 @@ import json import logging -import sqlite3 +try: + import sqlite3 +except ImportError: + pass from core import cli_utils from core.external_modules import pandas
diff --git a/tools/perf/cli_tools/soundwave/pandas_sqlite_test.py b/tools/perf/cli_tools/soundwave/pandas_sqlite_test.py index 648f420..8fdc19ff 100644 --- a/tools/perf/cli_tools/soundwave/pandas_sqlite_test.py +++ b/tools/perf/cli_tools/soundwave/pandas_sqlite_test.py
@@ -2,7 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import sqlite3 +try: + import sqlite3 +except ImportError: + pass import unittest from cli_tools.soundwave import pandas_sqlite
diff --git a/tools/perf/cli_tools/soundwave/tables/__init__.py b/tools/perf/cli_tools/soundwave/tables/__init__.py index e8528f3..44705e1 100644 --- a/tools/perf/cli_tools/soundwave/tables/__init__.py +++ b/tools/perf/cli_tools/soundwave/tables/__init__.py
@@ -5,7 +5,10 @@ import contextlib import os -import sqlite3 +try: + import sqlite3 +except ImportError: + pass from cli_tools.soundwave import pandas_sqlite from cli_tools.soundwave.tables import alerts
diff --git a/tools/perf/cli_tools/soundwave/worker_pool_test.py b/tools/perf/cli_tools/soundwave/worker_pool_test.py index 47197b3d..3e806fe 100644 --- a/tools/perf/cli_tools/soundwave/worker_pool_test.py +++ b/tools/perf/cli_tools/soundwave/worker_pool_test.py
@@ -5,7 +5,10 @@ import argparse import os import shutil -import sqlite3 +try: + import sqlite3 +except ImportError: + pass import tempfile import unittest
diff --git a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py index 489c754..ba64cc5 100644 --- a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py +++ b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
@@ -20,13 +20,17 @@ def setUp(self): self.maxDiff = None + # TODO(crbug.com/938487): This pattern of mocking leads to double-mocked + # functions (when inside a test case we mock something that has already been + # mocked), which cannot be reliably unmocked by calling + # mock.patch.stopall(), so then the mock leaks to other test cases run + # later and breaks them. self._check_log = mock.patch('core.cli_helpers.CheckLog').start() self._run = mock.patch('core.cli_helpers.Run').start() self._check_output = mock.patch('subprocess.check_output').start() self._check_call = mock.patch('subprocess.check_call').start() self._info = mock.patch('core.cli_helpers.Info').start() self._comment = mock.patch('core.cli_helpers.Comment').start() - self._ask = mock.patch('core.cli_helpers.Ask').start() self._open = mock.patch('__builtin__.open').start() datetime = mock.patch('datetime.datetime').start() datetime.now.return_value.strftime.return_value = '<tstamp>'
diff --git a/tools/perf/contrib/network_service/OWNERS b/tools/perf/contrib/network_service/OWNERS deleted file mode 100644 index c97b0ac..0000000 --- a/tools/perf/contrib/network_service/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -juncai@chromium.org - -file://services/network/OWNERS
diff --git a/tools/perf/contrib/network_service/__init__.py b/tools/perf/contrib/network_service/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tools/perf/contrib/network_service/__init__.py +++ /dev/null
diff --git a/tools/perf/contrib/network_service/loading.py b/tools/perf/contrib/network_service/loading.py deleted file mode 100644 index daa37c0..0000000 --- a/tools/perf/contrib/network_service/loading.py +++ /dev/null
@@ -1,238 +0,0 @@ -# Copyright 2017 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 copy -import json -import logging -import os -import traceback - -from benchmarks import loading - -from telemetry import benchmark -from telemetry.internal import story_runner -from telemetry.value import none_values -from telemetry.value.list_of_scalar_values import StandardDeviation - -from tracing.value import convert_chart_json - -def _ListSubtraction(diff_list, control_list): - """Subtract |control_list|'s elements from the corresponding elements in - |diff_list|, and store the results in |diff_list|. - - Lists may have different length and we will align with the shorter one. - e.g. 'timeToInteractive' may be missing for some runs. - """ - - min_len = min(len(diff_list), len(control_list)) - for i in xrange(min_len): - diff_list[i] = diff_list[i] - control_list[i] - while len(diff_list) > min_len: - diff_list.pop() - -def _PointSubtraction(diff_point, control_point): - """Subtract |control_point| from |diff_point| and store the result in - |diff_point|. - - Args: - diff_point: A chart point (could either be a story point (e.g. 'FIFA') or a - 'summary' point), will hold the result. - control_point: A chart point. - """ - - if diff_point['type'] == 'scalar': - diff_point['value'] = diff_point['value'] - control_point['value'] - elif diff_point['type'] == 'list_of_scalar_values': - # Points may have None 'values' regardless their types. - if not diff_point['values'] or not control_point['values']: - none_value_reason = ( - none_values.MERGE_FAILURE_REASON + - ' None values: %s' % repr([diff_point, control_point])) - diff_point['values'] = None - diff_point['std'] = None - diff_point['none_value_reason'] = none_value_reason - return - _ListSubtraction(diff_point['values'], control_point['values']) - diff_point['std'] = StandardDeviation(diff_point['values']) - else: - raise NotImplementedError('invalid point type: %s' % diff_point['type']) - -def _RenameChartsAndPointsWithSuffix(charts, suffix): - """Append |suffix| to all chart names (except 'trace') and point names - (except 'summary'). - - Args: - charts: A dictionary of charts. - suffix: A string suffix, e.g. '_control'. - """ - - # First rename all points except 'summary. - for chart_name in charts: - chart = charts[chart_name] - old_point_names = chart.keys() - for point_name in old_point_names: - if point_name == 'summary': - continue - chart[point_name + suffix] = chart[point_name] - chart.pop(point_name, None) - - # Then rename all charts except 'trace'. - old_chart_names = charts.keys() - for chart_name in old_chart_names: - if chart_name == 'trace': - continue - chart = charts[chart_name] - # Before adding the |suffix|, clean up |chart_name| by removing '@@' and - # any characters before it. - new_chart_name = chart_name.split('@@', 1)[-1] + suffix - for point_name in chart: - chart[point_name]['name'] = new_chart_name - charts[new_chart_name] = chart - charts.pop(chart_name, None) - -def _MergeCharts(dest_charts, source_charts): - """Update |dest_charts| with |source_charts| and merge 'trace'. - - Args: - dest_charts: A dictionary of charts, will hold the result. - source_charts: A dictionary of charts. - """ - - for chart_name in source_charts: - if chart_name == 'trace': - if chart_name not in dest_charts: - dest_charts[chart_name] = {} - dest_charts[chart_name].update(source_charts[chart_name]) - else: - dest_charts[chart_name] = source_charts[chart_name] - -def _MergeControlChartJsonIntoEnabled(enabled_chart_json, control_chart_json): - """Creates a diff chart_json from |enabled_chart_json| and - |control_chart_json|, then append appropriated suffix to all three chart_json - and merge them into |enabled_chart_json|. - - Args: - enabled_chart_json: A dictionary of charts, will hold the result.. - control_chart_json: A dictionary of charts. - """ - - # Leaving fields as-is other than 'charts' - enabled_charts = enabled_chart_json['charts'] - control_charts = control_chart_json['charts'] - diff_charts = copy.deepcopy(enabled_charts) - diff_charts['trace'] = {} - for chart_name in diff_charts.keys(): - if chart_name not in control_charts: - # Charts like 'timeToInteractive_std' may not be there if all values are - # None. - del diff_charts[chart_name] - continue - for point_name in diff_charts[chart_name].keys(): - if point_name not in control_charts[chart_name]: - del diff_charts[chart_name][point_name] - continue - _PointSubtraction(diff_charts[chart_name][point_name], - control_charts[chart_name][point_name]) - - _RenameChartsAndPointsWithSuffix(enabled_charts, '_enabled') - _RenameChartsAndPointsWithSuffix(control_charts, '_control') - _RenameChartsAndPointsWithSuffix(diff_charts, '_diff') - _MergeCharts(enabled_charts, control_charts) - _MergeCharts(enabled_charts, diff_charts) - -@benchmark.Info(emails=['juncai@chromium.org']) -class LoadingDesktopNetworkService(loading.LoadingDesktop): - """Measures loading performance of desktop sites, with the network service - enabled. - - Will run the test twice with feature on/off, and return the - difference as well as the original results. - """ - - def __init__(self, max_failures=None): - super(LoadingDesktopNetworkService, self).__init__(max_failures) - self.enable_feature = False - - @classmethod - def Name(cls): - return 'loading.desktop.network_service' - - def Run(self, finder_options): - """We shouldn't be overriding this according to - telemetry.benchmark.Benchmark""" - assert 'histograms' in finder_options.output_formats, ( - 'loading.desktop.network_service requires --output-format=histograms.') - - # feed the story_runner with 'chartjson' output formats. - # TODO(https://crbug.com/929765): Make loading.desktop.network_service - # benchmark produce histograms natively. - while 'histograms' in finder_options.output_formats: - finder_options.output_formats.remove('histograms') - finder_options.output_formats.append('chartjson') - - assert finder_options.output_dir - output_dir = finder_options.output_dir - temp_file_path = os.path.join(output_dir, 'results-chart.json') - - # Run test with feature disabled. - self.enable_feature = False - control_return_code = story_runner.RunBenchmark(self, finder_options) - if control_return_code != 0: - return control_return_code - control_chart_json = json.load(open(temp_file_path)) - - # Run test again with feature enabled. - self.enable_feature = True - enabled_return_code = story_runner.RunBenchmark(self, finder_options) - if enabled_return_code != 0: - return enabled_return_code - enabled_chart_json = json.load(open(temp_file_path)) - - logging.info('Starting to merge control chartjson into enabled chartjson') - try: - # Merge the result and compute the difference. - _MergeControlChartJsonIntoEnabled(enabled_chart_json, control_chart_json) - except Exception as e: - logging.error('exception merging two chart json: %s', repr(e)) - traceback.print_exc() - with open(temp_file_path, 'w') as f: - json.dump({ - 'control_chart_json': control_chart_json, - 'enabled_chart_json': enabled_chart_json}, - f, indent=2, separators=(',', ': ')) - f.write('\n') - return 1 - else: - logging.info('Finished merging chartjsons, writing back to disk') - with open(temp_file_path, 'w') as f: - json.dump(enabled_chart_json, f, indent=2, separators=(',', ': ')) - f.write('\n') - logging.info('Converting chartjsons to histograms') - histogram_result = convert_chart_json.ConvertChartJson(temp_file_path) - if histogram_result.returncode != 0: - logging.error('Error converting chart json to Histograms:\n' + - histogram_result.stdout) - return 1 - - temp_file_path = os.path.join(output_dir, 'histograms.json') - with open(temp_file_path, 'w') as f: - f.write(histogram_result.stdout) - - return 0 - - def SetExtraBrowserOptions(self, options): - if not self.enable_feature: - return - - enable_features_arg = '--enable-features=NetworkService' - - # If an "--enable-features" argument has been specified, append to the value - # list of that argument. - for arg in options.extra_browser_args: - if arg.startswith('--enable-features='): - options.extra_browser_args.remove(arg) - enable_features_arg = arg + ',NetworkService' - break - - options.AppendExtraBrowserArgs([enable_features_arg])
diff --git a/tools/perf/core/cli_helpers_unittest.py b/tools/perf/core/cli_helpers_unittest.py index e8f3754..c187f4fa 100644 --- a/tools/perf/core/cli_helpers_unittest.py +++ b/tools/perf/core/cli_helpers_unittest.py
@@ -17,38 +17,28 @@ cli_helpers.Colored('message', 'pink') @mock.patch('__builtin__.print') - # https://crbug.com/938487 - @decorators.Disabled('all') def testPrintsInfo(self, print_mock): cli_helpers.Info('foo {sval} {ival}', sval='s', ival=42) print_mock.assert_called_once_with('foo s 42') @mock.patch('__builtin__.print') - # https://crbug.com/938487 - @decorators.Disabled('all') def testPrintsComment(self, print_mock): cli_helpers.Comment('foo') print_mock.assert_called_once_with('\033[93mfoo\033[0m') @mock.patch('__builtin__.print') @mock.patch('sys.exit') - # https://crbug.com/938487 - @decorators.Disabled('all') def testFatal(self, sys_exit_mock, print_mock): cli_helpers.Fatal('foo') print_mock.assert_called_once_with('\033[91mfoo\033[0m') sys_exit_mock.assert_called_once() @mock.patch('__builtin__.print') - # https://crbug.com/938487 - @decorators.Disabled('all') def testPrintsError(self, print_mock): cli_helpers.Error('foo') print_mock.assert_called_once_with('\033[91mfoo\033[0m') @mock.patch('__builtin__.print') - # https://crbug.com/938487 - @decorators.Disabled('all') def testPrintsStep(self, print_mock): long_step_name = 'foobar' * 15 cli_helpers.Step(long_step_name) @@ -60,8 +50,8 @@ @mock.patch('__builtin__.print') @mock.patch('__builtin__.raw_input') - # https://crbug.com/938487 - @decorators.Disabled('all') + # https://crbug.com/938575. + @decorators.Disabled('chromeos') def testAskAgainOnInvalidAnswer(self, raw_input_mock, print_mock): raw_input_mock.side_effect = ['foobar', 'y'] self.assertTrue(cli_helpers.Ask('Ready?')) @@ -73,8 +63,8 @@ @mock.patch('__builtin__.print') @mock.patch('__builtin__.raw_input') - # https://crbug.com/938487 - @decorators.Disabled('all') + # https://crbug.com/938575. + @decorators.Disabled('chromeos') def testAskWithCustomAnswersAndDefault(self, raw_input_mock, print_mock): raw_input_mock.side_effect = [''] self.assertFalse( @@ -84,8 +74,8 @@ @mock.patch('__builtin__.print') @mock.patch('__builtin__.raw_input') - # https://crbug.com/938487 - @decorators.Disabled('all') + # https://crbug.com/938575. + @decorators.Disabled('chromeos') def testAskNoDefaultCustomAnswersAsList(self, raw_input_mock, print_mock): raw_input_mock.side_effect = ['', 'FoO'] self.assertEqual(cli_helpers.Ask('Ready?', ['foo', 'bar']), 'foo') @@ -95,8 +85,6 @@ mock.call('\033[96mReady? [foo/bar] \033[0m', end=' ') ]) - # https://crbug.com/938487 - @decorators.Disabled('all') def testAskWithInvalidDefaultAnswer(self): with self.assertRaises(ValueError): cli_helpers.Ask('Ready?', ['foo', 'bar'], 'baz') @@ -105,8 +93,6 @@ @mock.patch('subprocess.check_call') @mock.patch('__builtin__.open') @mock.patch('datetime.datetime') - # https://crbug.com/938487 - @decorators.Disabled('all') def testCheckLog( self, dt_mock, open_mock, check_call_mock, print_mock): file_mock = mock.Mock() @@ -133,8 +119,6 @@ @mock.patch('subprocess.check_call') @mock.patch('subprocess.call') @mock.patch('__builtin__.open') - # https://crbug.com/938487 - @decorators.Disabled('all') def testCheckLogError( self, open_mock, call_mock, check_call_mock, error_mock, print_mock): del print_mock, open_mock # Unused. @@ -153,8 +137,6 @@ @mock.patch('__builtin__.print') @mock.patch('subprocess.check_call') - # https://crbug.com/938487 - @decorators.Disabled('all') def testRun(self, check_call_mock, print_mock): check_call_mock.side_effect = [subprocess.CalledProcessError(87, ['cmd'])] with self.assertRaises(subprocess.CalledProcessError): @@ -165,23 +147,17 @@ @mock.patch('__builtin__.print') @mock.patch('subprocess.check_call') - # https://crbug.com/938487 - @decorators.Disabled('all') def testRunOkFail(self, check_call_mock, print_mock): del print_mock # Unused. check_call_mock.side_effect = [subprocess.CalledProcessError(87, ['cmd'])] cli_helpers.Run(['cmd'], ok_fail=True) - # https://crbug.com/938487 - @decorators.Disabled('all') def testRunWithNonListCommand(self): with self.assertRaises(ValueError): cli_helpers.Run('cmd with args') @mock.patch('__builtin__.print') @mock.patch('__builtin__.raw_input') - # https://crbug.com/938487 - @decorators.Disabled('all') def testPrompt(self, raw_input_mock, print_mock): raw_input_mock.side_effect = ['', '42'] self.assertEqual(cli_helpers.Prompt(
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 276756c1..eba2829 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -195,13 +195,9 @@ [ All ] rendering.mobile/paper_shadow [ Skip ] # Polymer test, needs to be modernized. [ All ] rendering.mobile/paper_tabs [ Skip ] # Polymer test, needs to be modernized. [ All ] rendering.mobile/paper_toggle_button [ Skip ] # Polymer test, needs to be modernized. -crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_15000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_20000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_40000_pixels_per_second [ Skip ] -crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_50000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_10000_pixels_per_second [ Skip ] -crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_05000_pixels_per_second [ Skip ] -crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_30000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_75000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_60000_pixels_per_second [ Skip ] crbug.com/785473 [ Android_Webview ] rendering.mobile/canvas_90000_pixels_per_second [ Skip ] @@ -414,22 +410,6 @@ ##### Perf FYI benchmarks go after here ##### -# Benchmark: loading.desktop.network_service -crbug.com/752611 [ Linux ] loading.desktop.network_service/uol.com.br_cold [ Skip ] -crbug.com/752611 [ Linux ] loading.desktop.network_service/uol.com.br_warm [ Skip ] -crbug.com/851171 [ Linux ] loading.desktop.network_service/Elmundo_cold [ Skip ] -crbug.com/851171 [ Linux ] loading.desktop.network_service/Elmundo_warm [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/AirBnB_cold [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/AirBnB_warm [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/Kenh14_cold [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/Kenh14_warm [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/Taobao_cold [ Skip ] -crbug.com/853835 [ Linux ] loading.desktop.network_service/Taobao_warm [ Skip ] -crbug.com/879833 [ Linux ] loading.desktop.network_service/Walgreens_cold [ Skip ] -crbug.com/879833 [ Linux ] loading.desktop.network_service/Walgreens_warm [ Skip ] -crbug.com/927758 [ Desktop ] loading.desktop.network_service/TheOnion_cold [ Skip ] -crbug.com/927758 [ Desktop ] loading.desktop.network_service/TheOnion_warm [ Skip ] - # Benchmark: loading.desktop_layout_ng crbug.com/879833 [ Linux ] loading.desktop_layout_ng/Walgreens_cold [ Skip ] crbug.com/879833 [ Linux ] loading.desktop_layout_ng/Walgreens_warm [ Skip ]
diff --git a/tools/perf/page_sets/rendering/tough_scrolling_cases.py b/tools/perf/page_sets/rendering/tough_scrolling_cases.py index faeba04f..38919040 100644 --- a/tools/perf/page_sets/rendering/tough_scrolling_cases.py +++ b/tools/perf/page_sets/rendering/tough_scrolling_cases.py
@@ -45,36 +45,18 @@ SPEED_IN_PIXELS_PER_SECOND = 10000 -class ScrollingText15000Page(ToughFastScrollingPage): - BASE_NAME = 'text_15000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text.html' - SPEED_IN_PIXELS_PER_SECOND = 15000 - - class ScrollingText20000Page(ToughFastScrollingPage): BASE_NAME = 'text_20000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text.html' SPEED_IN_PIXELS_PER_SECOND = 20000 -class ScrollingText30000Page(ToughFastScrollingPage): - BASE_NAME = 'text_30000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text.html' - SPEED_IN_PIXELS_PER_SECOND = 30000 - - class ScrollingText40000Page(ToughFastScrollingPage): BASE_NAME = 'text_40000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text.html' SPEED_IN_PIXELS_PER_SECOND = 40000 -class ScrollingText50000Page(ToughFastScrollingPage): - BASE_NAME = 'text_50000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text.html' - SPEED_IN_PIXELS_PER_SECOND = 50000 - - class ScrollingText60000Page(ToughFastScrollingPage): BASE_NAME = 'text_60000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text.html' @@ -107,13 +89,6 @@ SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE -class ScrollingTextHover15000Page(ToughFastScrollingPage): - BASE_NAME = 'text_hover_15000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_hover.html' - SPEED_IN_PIXELS_PER_SECOND = 15000 - SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE - - class ScrollingTextHover20000Page(ToughFastScrollingPage): BASE_NAME = 'text_hover_20000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_hover.html' @@ -121,13 +96,6 @@ SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE -class ScrollingTextHover30000Page(ToughFastScrollingPage): - BASE_NAME = 'text_hover_30000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_hover.html' - SPEED_IN_PIXELS_PER_SECOND = 30000 - SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE - - class ScrollingTextHover40000Page(ToughFastScrollingPage): BASE_NAME = 'text_hover_40000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_hover.html' @@ -135,13 +103,6 @@ SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE -class ScrollingTextHover50000Page(ToughFastScrollingPage): - BASE_NAME = 'text_hover_50000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_hover.html' - SPEED_IN_PIXELS_PER_SECOND = 50000 - SYNTHETIC_GESTURE_SOURCE = page_action.GESTURE_SOURCE_MOUSE - - class ScrollingTextHover60000Page(ToughFastScrollingPage): BASE_NAME = 'text_hover_60000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_hover.html' @@ -175,36 +136,18 @@ SPEED_IN_PIXELS_PER_SECOND = 10000 -class ScrollingTextRaster15000Page(ToughFastScrollingPage): - BASE_NAME = 'text_constant_full_page_raster_15000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' - SPEED_IN_PIXELS_PER_SECOND = 15000 - - class ScrollingTextRaster20000Page(ToughFastScrollingPage): BASE_NAME = 'text_constant_full_page_raster_20000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' SPEED_IN_PIXELS_PER_SECOND = 20000 -class ScrollingTextRaster30000Page(ToughFastScrollingPage): - BASE_NAME = 'text_constant_full_page_raster_30000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' - SPEED_IN_PIXELS_PER_SECOND = 30000 - - class ScrollingTextRaster40000Page(ToughFastScrollingPage): BASE_NAME = 'text_constant_full_page_raster_40000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' SPEED_IN_PIXELS_PER_SECOND = 40000 -class ScrollingTextRaster50000Page(ToughFastScrollingPage): - BASE_NAME = 'text_constant_full_page_raster_50000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' - SPEED_IN_PIXELS_PER_SECOND = 50000 - - class ScrollingTextRaster60000Page(ToughFastScrollingPage): BASE_NAME = 'text_constant_full_page_raster_60000_pixels_per_second' URL = 'file://../tough_scrolling_cases/text_constant_full_page_raster.html' @@ -235,36 +178,18 @@ SPEED_IN_PIXELS_PER_SECOND = 10000 -class ScrollingCanvas15000Page(ToughFastScrollingPage): - BASE_NAME = 'canvas_15000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/canvas.html' - SPEED_IN_PIXELS_PER_SECOND = 15000 - - class ScrollingCanvas20000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_20000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 20000 -class ScrollingCanvas30000Page(ToughFastScrollingPage): - BASE_NAME = 'canvas_30000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/canvas.html' - SPEED_IN_PIXELS_PER_SECOND = 30000 - - class ScrollingCanvas40000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_40000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html' SPEED_IN_PIXELS_PER_SECOND = 40000 -class ScrollingCanvas50000Page(ToughFastScrollingPage): - BASE_NAME = 'canvas_50000_pixels_per_second' - URL = 'file://../tough_scrolling_cases/canvas.html' - SPEED_IN_PIXELS_PER_SECOND = 50000 - - class ScrollingCanvas60000Page(ToughFastScrollingPage): BASE_NAME = 'canvas_60000_pixels_per_second' URL = 'file://../tough_scrolling_cases/canvas.html'
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py index a4e2aed..ab58f74 100755 --- a/tools/perf/process_perf_results.py +++ b/tools/perf/process_perf_results.py
@@ -300,15 +300,16 @@ f for f in listdir(task_output_dir) if not isfile(join(task_output_dir, f)) ] + benchmark_directory_list = [] benchmarks_shard_map_file = None for directory in directory_list: for f in listdir(join(task_output_dir, directory)): path = join(task_output_dir, directory, f) - if path.endswith('benchmarks_shard_map.json'): - benchmarks_shard_map_file = path - else: + if os.path.isdir(path): benchmark_directory_list.append(path) + elif path.endswith('benchmarks_shard_map.json'): + benchmarks_shard_map_file = path # Now create a map of benchmark name to the list of directories # the lists were written to. @@ -492,7 +493,7 @@ benchmark_name, directories, configuration_name, build_properties, output_json_file, service_account_file)) - # Kick off the uploads in mutliple processes + # Kick off the uploads in multiple processes pool = mp.Pool() try: async_result = pool.map_async( @@ -500,10 +501,11 @@ results = async_result.get(timeout=2000) except mp.TimeoutError: logging.error('Failed uploading benchmarks to perf dashboard in parallel') - pool.terminate() results = [] for benchmark_name in benchmark_directory_map: results.append((benchmark_name, False)) + finally: + pool.terminate() # Keep a mapping of benchmarks to their upload results benchmark_upload_result_map = {}
diff --git a/tools/perf/process_perf_results_unittest.py b/tools/perf/process_perf_results_unittest.py index 98ecfe19..31a5e7f 100755 --- a/tools/perf/process_perf_results_unittest.py +++ b/tools/perf/process_perf_results_unittest.py
@@ -118,7 +118,7 @@ }) return_code, benchmark_upload_result_map = ppr_module.process_perf_results( self.output_json, configuration_name='test-builder', - service_account_file = self.service_account_file, + service_account_file=self.service_account_file, build_properties=build_properties, task_output_dir=self.task_output_dir, smoke_test_mode=False)
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py index a78ea68..e0d03da 100644 --- a/tools/perf/scripts_smoke_unittest.py +++ b/tools/perf/scripts_smoke_unittest.py
@@ -69,35 +69,40 @@ options = options_for_unittests.GetCopy() browser_type = options.browser_type tempdir = tempfile.mkdtemp() - benchmark = 'dummy_benchmark.stable_benchmark_1' + benchmarks = ['dummy_benchmark.stable_benchmark_1', + 'dummy_benchmark.noisy_benchmark_1'] return_code, stdout = self.RunPerfScript( '../../testing/scripts/run_performance_tests.py ' '../../tools/perf/run_benchmark ' - '--benchmarks=dummy_benchmark.stable_benchmark_1 ' + '--benchmarks=%s ' '--browser=%s ' - '--isolated-script-test-repeat=2 ' '--isolated-script-test-also-run-disabled-tests ' '--isolated-script-test-output=%s' % ( + ','.join(benchmarks), browser_type, os.path.join(tempdir, 'output.json') )) self.assertEquals(return_code, 0, stdout) try: - # By design, run_performance_tests.py does not output test results - # to the location passed in by --isolated-script-test-output. Instead - # it uses that directory of that file and puts stuff in its own - # subdirectories for the purposes of merging later. - with open(os.path.join(tempdir, benchmark, 'test_results.json')) as f: + with open(os.path.join(tempdir, 'output.json')) as f: test_results = json.load(f) self.assertIsNotNone( test_results, 'json_test_results should be populated: ' + stdout) - test_repeats = test_results['num_failures_by_type']['PASS'] + benchmarks_run = [str(b) for b in test_results['tests'].keys()] + self.assertEqual(sorted(benchmarks_run), sorted(benchmarks)) + story_runs = test_results['num_failures_by_type']['PASS'] self.assertEqual( - test_repeats, 2, '--isolated-script-test-repeat=2 should work.') - with open(os.path.join(tempdir, benchmark, 'perf_results.json')) as f: - perf_results = json.load(f) - self.assertIsNotNone( - perf_results, 'json perf results should be populated: ' + stdout) + story_runs, 2, + 'Total runs should be 2 since each benchmark has one story.') + for benchmark in benchmarks: + with open(os.path.join(tempdir, benchmark, 'test_results.json')) as f: + test_results = json.load(f) + self.assertIsNotNone( + test_results, 'json_test_results should be populated: ' + stdout) + with open(os.path.join(tempdir, benchmark, 'perf_results.json')) as f: + perf_results = json.load(f) + self.assertIsNotNone( + perf_results, 'json perf results should be populated: ' + stdout) except IOError as e: self.fail('json_test_results should be populated: ' + stdout + str(e)) finally: @@ -130,6 +135,13 @@ expected_benchmark_folders = ( 'dummy_benchmark.stable_benchmark_1', 'dummy_benchmark.stable_benchmark_1.reference') + with open(os.path.join(tempdir, 'output.json')) as f: + test_results = json.load(f) + self.assertIsNotNone( + test_results, 'json_test_results should be populated: ' + stdout) + test_repeats = test_results['num_failures_by_type']['PASS'] + self.assertEqual( + test_repeats, 2, '--isolated-script-test-repeat=2 should work.') for folder in expected_benchmark_folders: with open(os.path.join(tempdir, folder, 'test_results.json')) as f: test_results = json.load(f) @@ -168,10 +180,10 @@ )) self.assertEquals(return_code, 0, stdout) try: - # By design, run_performance_tests.py does not output test results - # to the location passed in by --isolated-script-test-output. Instead - # it uses the directory of that file and puts stuff in its own - # subdirectories for the purposes of merging later. + with open(os.path.join(tempdir, 'output.json')) as f: + test_results = json.load(f) + self.assertIsNotNone( + test_results, 'json_test_results should be populated: ' + stdout) with open(os.path.join(tempdir, benchmark, 'test_results.json')) as f: test_results = json.load(f) self.assertIsNotNone(
diff --git a/tools/perf/testdata/task_output_dir/0/output.json b/tools/perf/testdata/task_output_dir/0/output.json new file mode 100644 index 0000000..88ed9fa --- /dev/null +++ b/tools/perf/testdata/task_output_dir/0/output.json
@@ -0,0 +1,2 @@ +["This is a fake json file to make sure that ", +"process_perf_results_unittest.py can handle it."]
diff --git a/tools/perf/testdata/task_output_dir/1/output.json b/tools/perf/testdata/task_output_dir/1/output.json new file mode 100644 index 0000000..88ed9fa --- /dev/null +++ b/tools/perf/testdata/task_output_dir/1/output.json
@@ -0,0 +1,2 @@ +["This is a fake json file to make sure that ", +"process_perf_results_unittest.py can handle it."]
diff --git a/tools/perf/testdata/task_output_dir/2/output.json b/tools/perf/testdata/task_output_dir/2/output.json new file mode 100644 index 0000000..88ed9fa --- /dev/null +++ b/tools/perf/testdata/task_output_dir/2/output.json
@@ -0,0 +1,2 @@ +["This is a fake json file to make sure that ", +"process_perf_results_unittest.py can handle it."]
diff --git a/tools/perf/testdata/task_output_dir/3/output.json b/tools/perf/testdata/task_output_dir/3/output.json new file mode 100644 index 0000000..88ed9fa --- /dev/null +++ b/tools/perf/testdata/task_output_dir/3/output.json
@@ -0,0 +1,2 @@ +["This is a fake json file to make sure that ", +"process_perf_results_unittest.py can handle it."]
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn index 90e9c726..c21a77a 100644 --- a/ui/accessibility/BUILD.gn +++ b/ui/accessibility/BUILD.gn
@@ -48,6 +48,7 @@ "ax_event_generator.h", "ax_export.h", "ax_language_info.h", + "ax_mode.cc", "ax_mode.h", "ax_mode_observer.h", "ax_node.cc", @@ -78,6 +79,9 @@ "ax_tree_id.h", "ax_tree_id_registry.cc", "ax_tree_id_registry.h", + "ax_tree_manager.h", + "ax_tree_manager_map.cc", + "ax_tree_manager_map.h", "ax_tree_observer.cc", "ax_tree_observer.h", "ax_tree_serializer.cc", @@ -108,6 +112,10 @@ "platform/ax_fragment_root_win.h", "platform/ax_platform_node_mac.h", "platform/ax_platform_node_mac.mm", + "platform/ax_platform_node_textprovider_win.cc", + "platform/ax_platform_node_textprovider_win.h", + "platform/ax_platform_node_textrangeprovider_win.cc", + "platform/ax_platform_node_textrangeprovider_win.h", "platform/ax_platform_node_win.cc", "platform/ax_platform_node_win.h", "platform/ax_platform_relation_win.cc", @@ -235,6 +243,8 @@ "mojom/ax_tree_id_mojom_traits_unittest.cc", "mojom/ax_tree_update_mojom_traits_unittest.cc", "platform/ax_fragment_root_win_unittest.cc", + "platform/ax_platform_node_textprovider_win_unittest.cc", + "platform/ax_platform_node_textrangeprovider_win_unittest.cc", "platform/ax_platform_node_unittest.cc", "platform/ax_platform_node_unittest.h", "platform/ax_platform_node_win_unittest.cc",
diff --git a/ui/accessibility/PRESUBMIT.py b/ui/accessibility/PRESUBMIT.py index b3038b8..b5bb4259 100644 --- a/ui/accessibility/PRESUBMIT.py +++ b/ui/accessibility/PRESUBMIT.py
@@ -159,7 +159,11 @@ # Look for lines of the form "static constexpr <type> NAME " m = re.search('static constexpr [\w]+ ([\w]+)', line) if m: - values.append(m.group(1)) + value = m.group(1) + # Skip first/last sentinels + if value == 'kFirstModeFlag' or value == 'kLastModeFlag': + continue + values.append(value) return values
diff --git a/ui/accessibility/ax_mode.cc b/ui/accessibility/ax_mode.cc new file mode 100644 index 0000000..bf37969 --- /dev/null +++ b/ui/accessibility/ax_mode.cc
@@ -0,0 +1,50 @@ +// Copyright 2019 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/accessibility/ax_mode.h" + +#include <vector> + +#include "base/strings/string_util.h" + +namespace ui { + +std::ostream& operator<<(std::ostream& stream, const AXMode& mode) { + std::vector<std::string> tokens; + + // Written as a loop with a switch so that this crashes if a new + // mode flag is added without adding support for logging it. + for (uint32_t mode_flag = AXMode::kFirstModeFlag; + mode_flag <= AXMode::kLastModeFlag; mode_flag = mode_flag << 1) { + const char* flag_name = nullptr; + switch (mode_flag) { + case AXMode::kNativeAPIs: + flag_name = "kNativeAPIs"; + break; + case AXMode::kWebContents: + flag_name = "kWebContents"; + break; + case AXMode::kInlineTextBoxes: + flag_name = "kInlineTextBoxes"; + break; + case AXMode::kScreenReader: + flag_name = "kScreenReader"; + break; + case AXMode::kHTML: + flag_name = "kHTML"; + break; + case AXMode::kLabelImages: + flag_name = "kLabelImages"; + break; + } + + DCHECK(flag_name); + + if (mode.has_mode(mode_flag)) + tokens.push_back(flag_name); + } + return stream << base::JoinString(tokens, " | "); +} + +} // namespace ui
diff --git a/ui/accessibility/ax_mode.h b/ui/accessibility/ax_mode.h index be3d44f2..5703942 100644 --- a/ui/accessibility/ax_mode.h +++ b/ui/accessibility/ax_mode.h
@@ -5,10 +5,20 @@ #ifndef UI_ACCESSIBILITY_AX_MODE_H_ #define UI_ACCESSIBILITY_AX_MODE_H_ +#include <stdint.h> + +#include <ostream> +#include <string> + +#include "base/logging.h" +#include "ui/accessibility/ax_export.h" + namespace ui { -class AXMode { +class AX_EXPORT AXMode { public: + static constexpr uint32_t kFirstModeFlag = 1 << 0; + // Native accessibility APIs, specific to each platform, are enabled. // When this mode is set that indicates the presence of a third-party // client accessing Chrome via accessibility APIs. However, unless one @@ -50,6 +60,11 @@ // The accessibility tree will contain automatic image annotations. static constexpr uint32_t kLabelImages = 1 << 5; + // Update this to include the last supported mode flag. If you add + // another, be sure to update the stream insertion operator for + // logging and debugging. + static constexpr uint32_t kLastModeFlag = 1 << 5; + constexpr AXMode() : flags_(0) {} constexpr AXMode(uint32_t flags) : flags_(flags) {} @@ -86,6 +101,9 @@ AXMode::kInlineTextBoxes | AXMode::kScreenReader | AXMode::kHTML); +// For debugging, test assertions, etc. +AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXMode& mode); + } // namespace ui #endif // UI_ACCESSIBILITY_AX_MODE_H_
diff --git a/ui/accessibility/ax_node_position.cc b/ui/accessibility/ax_node_position.cc index 3e52235..c9dbd0cb 100644 --- a/ui/accessibility/ax_node_position.cc +++ b/ui/accessibility/ax_node_position.cc
@@ -6,6 +6,7 @@ #include "base/strings/string_util.h" #include "ui/accessibility/ax_enums.mojom.h" +#include "ui/accessibility/ax_tree_manager_map.h" namespace ui { @@ -74,9 +75,18 @@ } AXNode* AXNodePosition::GetNodeInTree(AXTreeID tree_id, int32_t node_id) const { - if (!tree_ || node_id == INVALID_ANCHOR_ID) + if (node_id == INVALID_ANCHOR_ID) return nullptr; - return AXNodePosition::tree_->GetFromId(node_id); + + // Used for testing via AXNodePosition::SetTreeForTesting + if (AXNodePosition::tree_) + return AXNodePosition::tree_->GetFromId(node_id); + + AXTreeManager* manager = AXTreeManagerMap::GetInstance().GetManager(tree_id); + if (manager) + return manager->GetNodeFromTree(tree_id, node_id); + + return nullptr; } int AXNodePosition::MaxTextOffset() const {
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h index 4bd039c..80de0c9 100644 --- a/ui/accessibility/ax_position.h +++ b/ui/accessibility/ax_position.h
@@ -460,8 +460,9 @@ int adjusted_offset = AsTextPosition()->text_offset_; AXPositionInstance child_position = tree_position->CreateChildPositionAt(0); DCHECK(child_position); - for (int i = 1; i <= tree_position->child_index_ && - i < tree_position->AnchorChildCount(); + for (int i = 1; + i <= tree_position->child_index_ && + i < tree_position->AnchorChildCount() && adjusted_offset > 0; ++i) { adjusted_offset -= child_position->MaxTextOffsetInParent(); child_position = tree_position->CreateChildPositionAt(i); @@ -482,8 +483,9 @@ case AXPositionKind::NULL_POSITION: return CreateNullPosition(); case AXPositionKind::TREE_POSITION: - if (!AnchorChildCount()) + if (!AnchorChildCount()) { return CreateTreePosition(tree_id_, anchor_id_, BEFORE_TEXT); + } return CreateTreePosition(tree_id_, anchor_id_, 0 /* child_index */); case AXPositionKind::TEXT_POSITION: return CreateTextPosition(tree_id_, anchor_id_, 0 /* text_offset */,
diff --git a/ui/accessibility/ax_tree_id.h b/ui/accessibility/ax_tree_id.h index 3fd82a77..cbe94a4 100644 --- a/ui/accessibility/ax_tree_id.h +++ b/ui/accessibility/ax_tree_id.h
@@ -65,6 +65,14 @@ base::Optional<base::UnguessableToken> token_; }; +// For use in std::unordered_map. +struct AXTreeIDHash { + size_t operator()(const ui::AXTreeID& tree_id) const { + DCHECK(tree_id.type() == ax::mojom::AXTreeIDType::kToken); + return base::UnguessableTokenHash()(tree_id.token().value()); + } +}; + AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXTreeID& value); // The value to use when an AXTreeID is unknown.
diff --git a/ui/accessibility/ax_tree_manager.h b/ui/accessibility/ax_tree_manager.h new file mode 100644 index 0000000..5f96a65 --- /dev/null +++ b/ui/accessibility/ax_tree_manager.h
@@ -0,0 +1,26 @@ +// Copyright 2019 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_ACCESSIBILITY_AX_TREE_MANAGER_H_ +#define UI_ACCESSIBILITY_AX_TREE_MANAGER_H_ + +#include "base/macros.h" +#include "ui/accessibility/ax_node.h" +#include "ui/accessibility/ax_tree_id.h" + +namespace ui { + +// Each AXNode has access to its own tree, but a manager of multiple AXTrees +// is necessary for operations that span across trees. +class AX_EXPORT AXTreeManager { + public: + // Exposes the mapping between AXTreeID's and AXNodes based on a node_id. + // This allows for callers to access nodes outside of their own tree. + // Returns nullptr if the AXTreeID or node_id is not found. + virtual AXNode* GetNodeFromTree(AXTreeID tree_id, int32_t node_id) = 0; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_AX_TREE_MANAGER_H_
diff --git a/ui/accessibility/ax_tree_manager_map.cc b/ui/accessibility/ax_tree_manager_map.cc new file mode 100644 index 0000000..108c3d6 --- /dev/null +++ b/ui/accessibility/ax_tree_manager_map.cc
@@ -0,0 +1,36 @@ +// Copyright 2019 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/accessibility/ax_tree_manager_map.h" + +namespace ui { + +AXTreeManagerMap::AXTreeManagerMap() {} + +AXTreeManagerMap::~AXTreeManagerMap() {} + +AXTreeManagerMap& AXTreeManagerMap::GetInstance() { + static base::NoDestructor<AXTreeManagerMap> instance; + return *instance; +} + +void AXTreeManagerMap::AddTreeManager(AXTreeID tree_id, + AXTreeManager* manager) { + if (tree_id != AXTreeIDUnknown()) + map_[tree_id] = manager; +} + +void AXTreeManagerMap::RemoveTreeManager(AXTreeID tree_id) { + if (tree_id != AXTreeIDUnknown()) + map_.erase(tree_id); +} + +AXTreeManager* AXTreeManagerMap::GetManager(AXTreeID tree_id) { + if (tree_id == AXTreeIDUnknown()) + return nullptr; + + return map_[tree_id]; +} + +} // namespace ui
diff --git a/ui/accessibility/ax_tree_manager_map.h b/ui/accessibility/ax_tree_manager_map.h new file mode 100644 index 0000000..5e60e74 --- /dev/null +++ b/ui/accessibility/ax_tree_manager_map.h
@@ -0,0 +1,37 @@ +// Copyright 2019 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_ACCESSIBILITY_AX_TREE_MANAGER_MAP_H_ +#define UI_ACCESSIBILITY_AX_TREE_MANAGER_MAP_H_ + +#include <unordered_map> + +#include "base/macros.h" +#include "base/no_destructor.h" +#include "ui/accessibility/ax_tree_id.h" +#include "ui/accessibility/ax_tree_manager.h" + +namespace ui { + +// This class manages AXTreeManager instances. It is a singleton wrapper +// around a std::unordered_map. AXTreeID's are used as the key for the map. +// Since AXTreeID's might refer to AXTreeIDUnknown, callers should not expect +// AXTreeIDUnknown to map to a particular AXTreeManager. +class AX_EXPORT AXTreeManagerMap { + public: + AXTreeManagerMap(); + ~AXTreeManagerMap(); + + static AXTreeManagerMap& GetInstance(); + void AddTreeManager(AXTreeID tree_id, AXTreeManager* manager); + void RemoveTreeManager(AXTreeID tree_id); + AXTreeManager* GetManager(AXTreeID tree_id); + + private: + std::unordered_map<AXTreeID, AXTreeManager*, AXTreeIDHash> map_; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_AX_TREE_MANAGER_MAP_H_
diff --git a/ui/accessibility/platform/OWNERS b/ui/accessibility/platform/OWNERS new file mode 100644 index 0000000..b2c4d0f --- /dev/null +++ b/ui/accessibility/platform/OWNERS
@@ -0,0 +1,2 @@ +# For ATK / AuraLinux +mrobinson@igalia.com
diff --git a/ui/accessibility/platform/ax_fragment_root_win.cc b/ui/accessibility/platform/ax_fragment_root_win.cc index 4cab105..adcffb4e 100644 --- a/ui/accessibility/platform/ax_fragment_root_win.cc +++ b/ui/accessibility/platform/ax_fragment_root_win.cc
@@ -158,6 +158,16 @@ return platform_node_.Get(); } +void AXFragmentRootWin::SetParent(gfx::NativeViewAccessible parent) { + if (parent != nullptr) { + parent_ = static_cast<ui::AXPlatformNodeWin*>( + ui::AXPlatformNode::FromNativeViewAccessible(parent)); + DCHECK(parent_); + } else { + parent_ = nullptr; + } +} + void AXFragmentRootWin::SetChild(gfx::NativeViewAccessible child) { if (child != nullptr) { child_ = static_cast<ui::AXPlatformNodeWin*>( @@ -168,6 +178,14 @@ } } +gfx::NativeViewAccessible AXFragmentRootWin::GetParent() { + if (parent_ != nullptr) { + return parent_->GetNativeViewAccessible(); + } + + return nullptr; +} + int AXFragmentRootWin::GetChildCount() { return (child_ != nullptr) ? 1 : 0; }
diff --git a/ui/accessibility/platform/ax_fragment_root_win.h b/ui/accessibility/platform/ax_fragment_root_win.h index dc323b55..0682bca 100644 --- a/ui/accessibility/platform/ax_fragment_root_win.h +++ b/ui/accessibility/platform/ax_fragment_root_win.h
@@ -41,6 +41,10 @@ // Return the NativeViewAccessible for this fragment root. gfx::NativeViewAccessible GetNativeViewAccessible(); + // The legacy window needs to provide navigation to its parent for tree + // linkage to be correct. + void SetParent(gfx::NativeViewAccessible parent); + // The sole child of a fragment root is permitted to change during the // fragment root's lifetime. This will happen, for example, on a web content // navigation. @@ -48,6 +52,7 @@ private: // AXPlatformNodeDelegate overrides. + gfx::NativeViewAccessible GetParent() override; int GetChildCount() override; gfx::NativeViewAccessible ChildAtIndex(int index) override; gfx::NativeViewAccessible HitTestSync(int x, int y) override; @@ -56,6 +61,7 @@ gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; Microsoft::WRL::ComPtr<ui::AXFragmentRootPlatformNodeWin> platform_node_; + Microsoft::WRL::ComPtr<ui::AXPlatformNodeWin> parent_; Microsoft::WRL::ComPtr<ui::AXPlatformNodeWin> child_; ui::AXUniqueId unique_id_; gfx::AcceleratedWidget widget_;
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 1dc99c7..335dec19f 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -318,6 +318,10 @@ return delegate_->AccessibilityPerformAction(action_data); } +bool AXPlatformNodeBase::IsDocument() const { + return ui::IsDocument(GetData().role); +} + bool AXPlatformNodeBase::IsTextOnlyObject() const { return GetData().role == ax::mojom::Role::kStaticText || GetData().role == ax::mojom::Role::kLineBreak ||
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index 2c5c3f36..d7fd18f 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -222,6 +222,7 @@ AXPlatformNodeDelegate* delegate_; protected: + bool IsDocument() const; bool IsTextOnlyObject() const; bool IsPlainTextField() const; // Is in a focused textfield with a related suggestion popup available,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h index 1ec22a1..3e7f481 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate.h +++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -11,6 +11,8 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" +#include "ui/accessibility/ax_node_position.h" +#include "ui/accessibility/ax_position.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/gfx/geometry/vector2d.h" @@ -53,6 +55,12 @@ // Get the accessibility tree data for this node. virtual const AXTreeData& GetTreeData() const = 0; + // Creates a text position rooted at this object. + virtual AXNodePosition::AXPositionInstance CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity = + ax::mojom::TextAffinity::kDownstream) const = 0; + // Get the accessibility node for the NSWindow the node is contained in. This // method is only meaningful on macOS. virtual gfx::NativeViewAccessible GetNSWindow() = 0;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc index 91dd3a1..21d9fe2 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -28,6 +28,13 @@ return *empty_data; } +AXNodePosition::AXPositionInstance +AXPlatformNodeDelegateBase::CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity) const { + return AXNodePosition::CreateNullPosition(); +} + gfx::NativeViewAccessible AXPlatformNodeDelegateBase::GetNSWindow() { return nullptr; }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h index d027544..34baed1b 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.h +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -29,6 +29,12 @@ // Get the accessibility tree data for this node. const AXTreeData& GetTreeData() const override; + // Creates a text position rooted at this object. + AXNodePosition::AXPositionInstance CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity = + ax::mojom::TextAffinity::kDownstream) const override; + // See comments in AXPlatformNodeDelegate. gfx::NativeViewAccessible GetNSWindow() override;
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc new file mode 100644 index 0000000..2817508 --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -0,0 +1,130 @@ +// Copyright 2019 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/accessibility/platform/ax_platform_node_textprovider_win.h" + +#include <utility> + +#include "ui/accessibility/ax_node_position.h" +#include "ui/accessibility/platform/ax_platform_node_delegate.h" +#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h" + +#define UIA_VALIDATE_TEXTPROVIDER_CALL() \ + if (!owner()->GetDelegate()) \ + return UIA_E_ELEMENTNOTAVAILABLE; + +namespace ui { + +AXPlatformNodeTextProviderWin::AXPlatformNodeTextProviderWin() { + DVLOG(1) << __func__; +} + +AXPlatformNodeTextProviderWin::~AXPlatformNodeTextProviderWin() {} + +// static +HRESULT AXPlatformNodeTextProviderWin::Create(ui::AXPlatformNodeWin* owner, + IUnknown** provider) { + CComObject<AXPlatformNodeTextProviderWin>* text_provider = nullptr; + HRESULT hr = + CComObject<AXPlatformNodeTextProviderWin>::CreateInstance(&text_provider); + if (SUCCEEDED(hr)) { + DCHECK(text_provider); + text_provider->owner_ = owner; + hr = text_provider->QueryInterface(IID_PPV_ARGS(provider)); + } + + return hr; +} + +// +// ITextProvider methods. +// + +STDMETHODIMP AXPlatformNodeTextProviderWin::GetSelection( + SAFEARRAY** selection) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::GetVisibleRanges( + SAFEARRAY** visible_ranges) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::RangeFromChild( + IRawElementProviderSimple* child, + ITextRangeProvider** range) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::RangeFromPoint( + UiaPoint uia_point, + ITextRangeProvider** range) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::get_DocumentRange( + ITextRangeProvider** range) { + UIA_VALIDATE_TEXTPROVIDER_CALL(); + DVLOG(1) << __func__; + + *range = nullptr; + + // Start and end should be leaf text positions that span the beginning + // and end of text content within a node for get_DocumentRange. The start + // position should be the directly first child and the end position should + // be the deepest last child node. + AXNodePosition::AXPositionInstance start = + owner()->GetDelegate()->CreateTextPositionAt(0)->AsLeafTextPosition(); + + AXNodePosition::AXPositionInstance end; + if (owner()->GetChildCount() == 0) { + end = start->CreatePositionAtEndOfAnchor()->AsLeafTextPosition(); + } else { + AXPlatformNode* deepest_last_child = + AXPlatformNode::FromNativeViewAccessible( + owner()->ChildAtIndex(owner()->GetChildCount() - 1)); + + while (deepest_last_child && + deepest_last_child->GetDelegate()->GetChildCount() > 0) { + deepest_last_child = + AXPlatformNode::FromNativeViewAccessible(owner()->ChildAtIndex( + deepest_last_child->GetDelegate()->GetChildCount() - 1)); + } + end = deepest_last_child->GetDelegate() + ->CreateTextPositionAt(0) + ->CreatePositionAtEndOfAnchor() + ->AsLeafTextPosition(); + } + + return AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider( + owner_, std::move(start), std::move(end), range); +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::get_SupportedTextSelection( + enum SupportedTextSelection* text_selection) { + UIA_VALIDATE_TEXTPROVIDER_CALL(); + + *text_selection = SupportedTextSelection_Single; + return S_OK; +} + +// +// ITextEditProvider methods. +// + +STDMETHODIMP AXPlatformNodeTextProviderWin::GetActiveComposition( + ITextRangeProvider** range) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextProviderWin::GetConversionTarget( + ITextRangeProvider** range) { + return E_NOTIMPL; +} + +ui::AXPlatformNodeWin* AXPlatformNodeTextProviderWin::owner() const { + return owner_; +} + +} // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.h b/ui/accessibility/platform/ax_platform_node_textprovider_win.h new file mode 100644 index 0000000..394d4d1 --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.h
@@ -0,0 +1,62 @@ +// Copyright 2019 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_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTPROVIDER_WIN_H_ +#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTPROVIDER_WIN_H_ + +#include "ui/accessibility/platform/ax_platform_node_win.h" + +namespace ui { +class AXPlatformNodeTextProviderWin + : public CComObjectRootEx<CComMultiThreadModel>, + public ITextEditProvider { + public: + BEGIN_COM_MAP(AXPlatformNodeTextProviderWin) + COM_INTERFACE_ENTRY(ITextProvider) + COM_INTERFACE_ENTRY(ITextEditProvider) + END_COM_MAP() + + AXPlatformNodeTextProviderWin(); + ~AXPlatformNodeTextProviderWin(); + + // Creates an instance of the class. + // Returns true on success + static HRESULT Create(ui::AXPlatformNodeWin* owner, IUnknown** provider); + + // + // ITextProvider methods. + // + + STDMETHOD(GetSelection)(SAFEARRAY** selection) override; + + STDMETHOD(GetVisibleRanges)(SAFEARRAY** visible_ranges) override; + + STDMETHOD(RangeFromChild) + (IRawElementProviderSimple* child, ITextRangeProvider** range) override; + + STDMETHOD(RangeFromPoint) + (UiaPoint point, ITextRangeProvider** range) override; + + STDMETHOD(get_DocumentRange)(ITextRangeProvider** range) override; + + STDMETHOD(get_SupportedTextSelection) + (enum SupportedTextSelection* text_selection) override; + + // + // ITextEditProvider methods. + // + + STDMETHOD(GetActiveComposition)(ITextRangeProvider** range) override; + + STDMETHOD(GetConversionTarget)(ITextRangeProvider** range) override; + + private: + ui::AXPlatformNodeWin* owner() const; + + CComPtr<ui::AXPlatformNodeWin> owner_; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTPROVIDER_WIN_H_
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc new file mode 100644 index 0000000..8e653f5 --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -0,0 +1,71 @@ +// Copyright 2019 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/accessibility/platform/ax_platform_node_win_unittest.h" + +#include <UIAutomationClient.h> +#include "base/win/scoped_bstr.h" +#include "ui/accessibility/platform/ax_fragment_root_win.h" +#include "ui/base/win/accessibility_misc_utils.h" + +using Microsoft::WRL::ComPtr; + +namespace ui { + +class AXPlatformNodeTextProviderTest : public ui::AXPlatformNodeWinTest {}; + +TEST_F(AXPlatformNodeTextProviderTest, TestITextProviderDocumentRange) { + ui::AXNodeData text_data; + text_data.id = 2; + text_data.role = ax::mojom::Role::kStaticText; + text_data.SetName("some text"); + + ui::AXNodeData root_data; + root_data.id = 1; + root_data.SetName("Document"); + root_data.role = ax::mojom::Role::kRootWebArea; + root_data.child_ids.push_back(2); + + Init(root_data, text_data); + + ComPtr<IRawElementProviderSimple> root_node = + GetRootIRawElementProviderSimple(); + + ComPtr<ITextProvider> text_provider; + EXPECT_HRESULT_SUCCEEDED( + root_node->GetPatternProvider(UIA_TextPatternId, &text_provider)); + + ComPtr<ITextRangeProvider> text_range_provider; + EXPECT_HRESULT_SUCCEEDED( + text_provider->get_DocumentRange(&text_range_provider)); +} + +TEST_F(AXPlatformNodeTextProviderTest, TestITextProviderSupportedSelection) { + ui::AXNodeData text_data; + text_data.id = 2; + text_data.role = ax::mojom::Role::kStaticText; + text_data.SetName("some text"); + + ui::AXNodeData root_data; + root_data.id = 1; + root_data.SetName("Document"); + root_data.role = ax::mojom::Role::kRootWebArea; + root_data.child_ids.push_back(2); + + Init(root_data, text_data); + + ComPtr<IRawElementProviderSimple> root_node = + GetRootIRawElementProviderSimple(); + + ComPtr<ITextProvider> text_provider; + EXPECT_HRESULT_SUCCEEDED( + root_node->GetPatternProvider(UIA_TextPatternId, &text_provider)); + + SupportedTextSelection text_selection_mode; + EXPECT_HRESULT_SUCCEEDED( + text_provider->get_SupportedTextSelection(&text_selection_mode)); + EXPECT_EQ(text_selection_mode, SupportedTextSelection_Single); +} + +} // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc new file mode 100644 index 0000000..274fa573 --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -0,0 +1,180 @@ +// Copyright 2019 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/accessibility/platform/ax_platform_node_textrangeprovider_win.h" + +#include <utility> +#include <vector> + +#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \ + if (!owner() || !owner()->GetDelegate() || !start_->GetAnchor() || \ + !end_->GetAnchor()) \ + return UIA_E_ELEMENTNOTAVAILABLE; + +namespace ui { + +AXPlatformNodeTextRangeProviderWin::AXPlatformNodeTextRangeProviderWin() { + DVLOG(1) << __func__; +} + +AXPlatformNodeTextRangeProviderWin::~AXPlatformNodeTextRangeProviderWin() {} + +HRESULT AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider( + ui::AXPlatformNodeWin* owner, + AXNodePosition::AXPositionInstance start, + AXNodePosition::AXPositionInstance end, + ITextRangeProvider** provider) { + CComObject<AXPlatformNodeTextRangeProviderWin>* text_range_provider = nullptr; + HRESULT hr = CComObject<AXPlatformNodeTextRangeProviderWin>::CreateInstance( + &text_range_provider); + if (SUCCEEDED(hr)) { + DCHECK(text_range_provider); + text_range_provider->owner_ = owner; + text_range_provider->start_ = std::move(start); + text_range_provider->end_ = std::move(end); + text_range_provider->AddRef(); + *provider = text_range_provider; + } + + return hr; +} + +// +// ITextRangeProvider methods. +// +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::Clone( + ITextRangeProvider** clone) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::Compare( + __in ITextRangeProvider* other, + __out BOOL* result) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::CompareEndpoints( + TextPatternRangeEndpoint endpoint, + __in ITextRangeProvider* other, + TextPatternRangeEndpoint targetEndpoint, + __out int* result) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnit( + TextUnit unit) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::FindAttribute( + TEXTATTRIBUTEID text_attribute_id, + VARIANT val, + BOOL backward, + ITextRangeProvider** result) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::FindText( + BSTR string, + BOOL backwards, + BOOL ignore_case, + ITextRangeProvider** result) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetAttributeValue( + TEXTATTRIBUTEID attributeId, + VARIANT* value) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetBoundingRectangles( + SAFEARRAY** rectangles) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetEnclosingElement( + IRawElementProviderSimple** element) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetText(int max_count, + BSTR* text) { + UIA_VALIDATE_TEXTRANGEPROVIDER_CALL(); + + // -1 is a valid value that signifies that the caller wants complete text. + // Any other negative value is invalid. + if (max_count < -1 || !text) + return E_INVALIDARG; + + base::string16 full_text = GetString(); + if (!full_text.empty()) { + size_t length = full_text.length(); + + if (max_count != -1 && max_count < static_cast<int>(length)) + *text = SysAllocStringLen(full_text.c_str(), max_count); + else + *text = SysAllocStringLen(full_text.c_str(), length); + } else { + *text = SysAllocString(L""); + } + + return S_OK; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit, + int count, + int* units_moved) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnit( + TextPatternRangeEndpoint endpoint, + TextUnit unit, + int count, + int* units_moved) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::MoveEndpointByRange( + TextPatternRangeEndpoint endpoint, + ITextRangeProvider* other, + TextPatternRangeEndpoint targetEndpoint) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::Select() { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::AddToSelection() { + return UIA_E_INVALIDOPERATION; // not supporting disjoint text selections +} + +STDMETHODIMP +AXPlatformNodeTextRangeProviderWin::RemoveFromSelection() { + return UIA_E_INVALIDOPERATION; // not supporting disjoint text selections +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::ScrollIntoView( + BOOL align_to_top) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetChildren( + SAFEARRAY** children) { + return E_NOTIMPL; +} + +base::string16 AXPlatformNodeTextRangeProviderWin::GetString() { + AXNodeRange range(start_->Clone(), end_->Clone()); + + return range.GetText(); +} + +ui::AXPlatformNodeWin* AXPlatformNodeTextRangeProviderWin::owner() const { + return owner_; +} + +} // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h new file mode 100644 index 0000000..927df09a --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -0,0 +1,99 @@ +// Copyright 2019 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_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTRANGEPROVIDER_WIN_H_ +#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTRANGEPROVIDER_WIN_H_ + +#include <tuple> +#include <vector> + +#include "ui/accessibility/ax_node_position.h" +#include "ui/accessibility/ax_position.h" +#include "ui/accessibility/ax_range.h" +#include "ui/accessibility/platform/ax_platform_node_win.h" + +namespace ui { +class __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1")) + AXPlatformNodeTextRangeProviderWin + : public CComObjectRootEx<CComMultiThreadModel>, + public ITextRangeProvider { + public: + BEGIN_COM_MAP(AXPlatformNodeTextRangeProviderWin) + COM_INTERFACE_ENTRY(ITextRangeProvider) + COM_INTERFACE_ENTRY(AXPlatformNodeTextRangeProviderWin) + END_COM_MAP() + + AXPlatformNodeTextRangeProviderWin(); + ~AXPlatformNodeTextRangeProviderWin(); + + // Creates an instance of the class. + // Returns a successful HRESULT on success + static HRESULT CreateTextRangeProvider( + ui::AXPlatformNodeWin* owner, + AXNodePosition::AXPositionInstance start, + AXNodePosition::AXPositionInstance end, + ITextRangeProvider** provider); + + // + // ITextRangeProvider methods. + // + + STDMETHODIMP Clone(ITextRangeProvider** clone) override; + STDMETHODIMP Compare(ITextRangeProvider* other, BOOL* result) override; + STDMETHODIMP + CompareEndpoints(TextPatternRangeEndpoint endpoint, + ITextRangeProvider* other, + TextPatternRangeEndpoint targetEndpoint, + int* result) override; + STDMETHODIMP ExpandToEnclosingUnit(TextUnit unit) override; + STDMETHODIMP + FindAttribute(TEXTATTRIBUTEID attributeId, + VARIANT val, + BOOL backward, + ITextRangeProvider** result) override; + STDMETHODIMP + FindText(BSTR string, + BOOL backwards, + BOOL ignore_case, + ITextRangeProvider** result) override; + STDMETHODIMP GetAttributeValue(TEXTATTRIBUTEID attributeId, + VARIANT* value) override; + STDMETHODIMP + GetBoundingRectangles(SAFEARRAY** rectangles) override; + STDMETHODIMP + GetEnclosingElement(IRawElementProviderSimple** element) override; + STDMETHODIMP GetText(int max_count, BSTR* text) override; + STDMETHODIMP Move(TextUnit unit, int count, int* units_moved) override; + STDMETHODIMP + MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, + TextUnit unit, + int count, + int* units_moved) override; + STDMETHODIMP + MoveEndpointByRange(TextPatternRangeEndpoint endpoint, + ITextRangeProvider* other, + TextPatternRangeEndpoint targetEndpoint) override; + STDMETHODIMP Select() override; + STDMETHODIMP AddToSelection() override; + STDMETHODIMP RemoveFromSelection() override; + STDMETHODIMP ScrollIntoView(BOOL align_to_top) override; + STDMETHODIMP GetChildren(SAFEARRAY** children) override; + + private: + base::string16 GetString(); + ui::AXPlatformNodeWin* owner() const; + + using AXPositionInstance = AXNodePosition::AXPositionInstance; + using AXNodeRange = AXRange<AXNodePosition::AXPositionInstance::element_type>; + using AXPositionInstancePair = + std::tuple<AXPositionInstance, AXPositionInstance>; + + AXNodePosition::AXPositionInstance start_; + AXNodePosition::AXPositionInstance end_; + CComPtr<ui::AXPlatformNodeWin> owner_; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_TEXTRANGEPROVIDER_WIN_H_
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc new file mode 100644 index 0000000..0b6a10d --- /dev/null +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -0,0 +1,149 @@ +// Copyright 2019 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/accessibility/platform/ax_platform_node_win_unittest.h" + +#include <UIAutomationClient.h> +#include <UIAutomationCoreApi.h> +#include "base/win/atl.h" +#include "base/win/scoped_bstr.h" +#include "ui/accessibility/platform/ax_fragment_root_win.h" + +using Microsoft::WRL::ComPtr; + +namespace ui { + +class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {}; + +TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetText) { + ui::AXNodeData text_data; + text_data.id = 2; + text_data.role = ax::mojom::Role::kStaticText; + text_data.SetName("some text"); + + ui::AXNodeData more_text_data; + more_text_data.id = 3; + more_text_data.role = ax::mojom::Role::kStaticText; + more_text_data.SetName("more text"); + + ui::AXNodeData root_data; + root_data.id = 1; + root_data.role = ax::mojom::Role::kRootWebArea; + root_data.child_ids.push_back(2); + root_data.child_ids.push_back(3); + + ui::AXTreeUpdate update; + ui::AXTreeData tree_data; + tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID(); + update.tree_data = tree_data; + update.has_tree_data = true; + update.root_id = root_data.id; + update.nodes.push_back(root_data); + update.nodes.push_back(text_data); + update.nodes.push_back(more_text_data); + + Init(update); + + AXNode* root_node = GetRootNode(); + AXNodePosition::SetTreeForTesting(tree_.get()); + AXNode* text_node = root_node->children()[0]; + + ComPtr<IRawElementProviderSimple> text_node_raw = + QueryInterfaceFromNode<IRawElementProviderSimple>(text_node); + + ComPtr<ITextProvider> text_provider; + EXPECT_HRESULT_SUCCEEDED( + text_node_raw->GetPatternProvider(UIA_TextPatternId, &text_provider)); + + ComPtr<ITextRangeProvider> text_range_provider; + EXPECT_HRESULT_SUCCEEDED( + text_provider->get_DocumentRange(&text_range_provider)); + + base::win::ScopedBstr text_content; + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(-1, text_content.Receive())); + EXPECT_STREQ(text_content, L"some text"); + text_content.Reset(); + + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(4, text_content.Receive())); + EXPECT_STREQ(text_content, L"some"); + text_content.Reset(); + + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(0, text_content.Receive())); + EXPECT_STREQ(text_content, L""); + text_content.Reset(); + + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(9, text_content.Receive())); + EXPECT_STREQ(text_content, L"some text"); + text_content.Reset(); + + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(10, text_content.Receive())); + EXPECT_STREQ(text_content, L"some text"); + text_content.Reset(); + + EXPECT_HRESULT_FAILED(text_range_provider->GetText(-1, nullptr)); + + EXPECT_HRESULT_FAILED( + text_range_provider->GetText(-2, text_content.Receive())); + text_content.Reset(); + + Microsoft::WRL::ComPtr<IRawElementProviderSimple> root_node_raw = + QueryInterfaceFromNode<IRawElementProviderSimple>(root_node); + + Microsoft::WRL::ComPtr<ITextProvider> document_provider; + EXPECT_HRESULT_SUCCEEDED( + root_node_raw->GetPatternProvider(UIA_TextPatternId, &document_provider)); + + ComPtr<ITextRangeProvider> document_textrange; + EXPECT_HRESULT_SUCCEEDED( + document_provider->get_DocumentRange(&document_textrange)); + + EXPECT_HRESULT_SUCCEEDED( + document_textrange->GetText(-1, text_content.Receive())); + EXPECT_STREQ(text_content, L"some textmore text"); + text_content.Reset(); + + AXNodePosition::SetTreeForTesting(nullptr); +} + +TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelection) { + ui::AXNodeData text_data; + text_data.id = 2; + text_data.role = ax::mojom::Role::kStaticText; + text_data.SetName("some text"); + + ui::AXNodeData root_data; + root_data.id = 1; + root_data.role = ax::mojom::Role::kRootWebArea; + root_data.child_ids.push_back(2); + + Init(root_data, text_data); + + AXNode* root_node = GetRootNode(); + AXNodePosition::SetTreeForTesting(tree_.get()); + + ComPtr<IRawElementProviderSimple> root_node_raw = + QueryInterfaceFromNode<IRawElementProviderSimple>(root_node); + + ComPtr<ITextProvider> document_provider; + EXPECT_HRESULT_SUCCEEDED( + root_node_raw->GetPatternProvider(UIA_TextPatternId, &document_provider)); + + ComPtr<ITextRangeProvider> text_range_provider; + EXPECT_HRESULT_SUCCEEDED( + document_provider->get_DocumentRange(&text_range_provider)); + + ASSERT_EQ(text_range_provider->AddToSelection(), + static_cast<HRESULT>(UIA_E_INVALIDOPERATION)); + ASSERT_EQ(text_range_provider->RemoveFromSelection(), + static_cast<HRESULT>(UIA_E_INVALIDOPERATION)); + + AXNodePosition::SetTreeForTesting(nullptr); +} + +} // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 3d46535..763b3bd2 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -15,6 +15,7 @@ #include <vector> #include "base/lazy_instance.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -25,11 +26,13 @@ #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_mode_observer.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/platform/ax_fragment_root_win.h" #include "ui/accessibility/platform/ax_platform_node_delegate.h" +#include "ui/accessibility/platform/ax_platform_node_textprovider_win.h" #include "ui/accessibility/platform/ax_platform_relation_win.h" #include "ui/base/win/atl_module.h" #include "ui/display/win/screen_win.h" @@ -397,6 +400,21 @@ return uia_array; } +SAFEARRAY* AXPlatformNodeWin::CreateClickablePointArray() { + SAFEARRAY* clickable_point_array = SafeArrayCreateVector(VT_R8, 0, 2); + gfx::Point center = + GetDelegate()->GetUnclippedScreenBoundsRect().CenterPoint(); + + double* double_array; + SafeArrayAccessData(clickable_point_array, + reinterpret_cast<void**>(&double_array)); + double_array[0] = center.x(); + double_array[1] = center.y(); + SafeArrayUnaccessData(clickable_point_array); + + return clickable_point_array; +} + gfx::Vector2d AXPlatformNodeWin::CalculateUIAScrollPoint( const ScrollAmount horizontal_amount, const ScrollAmount vertical_amount) const { @@ -3558,6 +3576,14 @@ } break; + case UIA_TextEditPatternId: + case UIA_TextPatternId: + if (IsTextOnlyObject() || IsDocument() || + HasBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot)) { + return AXPlatformNodeTextProviderWin::Create(this, result); + } + break; + case UIA_TogglePatternId: if (SupportsToggle(data.role)) { AddRef(); @@ -3589,8 +3615,6 @@ case UIA_SpreadsheetItemPatternId: case UIA_StylesPatternId: case UIA_TextChildPatternId: - case UIA_TextEditPatternId: - case UIA_TextPatternId: case UIA_TextPattern2Id: case UIA_TransformPattern2Id: case UIA_VirtualizedItemPatternId: @@ -3602,6 +3626,18 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id, VARIANT* result) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PROPERTY_VALUE); + + constexpr long kFirstKnownUiaPropertyId = UIA_RuntimeIdPropertyId; + constexpr long kLastKnownUiaPropertyId = UIA_IsDialogPropertyId; + if (property_id >= kFirstKnownUiaPropertyId && + property_id <= kLastKnownUiaPropertyId) { + base::UmaHistogramSparse("Accessibility.WinAPIs.GetPropertyValue", + property_id); + } else { + // Collapse all unknown property IDs into a single bucket. + base::UmaHistogramSparse("Accessibility.WinAPIs.GetPropertyValue", 0); + } + UIA_VALIDATE_CALL_1_ARG(result); const AXNodeData& data = GetData(); @@ -3635,7 +3671,8 @@ break; case UIA_ClickablePointPropertyId: - // TODO(suproteem) + result->vt = VT_ARRAY | VT_R8; + result->parray = CreateClickablePointArray(); break; case UIA_ControllerForPropertyId:
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index 4c37ccb..b2076fd 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -1067,6 +1067,10 @@ // of |AXNode| ids. SAFEARRAY* CreateUIAElementsArrayFromIdVector(std::vector<int32_t>& ids); + // Return an array that contains the center x, y coordinates of the + // clickable point. + SAFEARRAY* CreateClickablePointArray(); + // Returns the scroll offsets to which UI Automation should scroll an // accessible object, given the horizontal and vertical scroll amounts. gfx::Vector2d CalculateUIAScrollPoint(
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index ae1d66c..0c7805a 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> +#include "base/test/metrics/histogram_tester.h" #include "base/win/atl.h" #include "base/win/scoped_bstr.h" #include "base/win/scoped_variant.h" @@ -71,6 +72,31 @@ EXPECT_EQ(expectedVariant.ptr()->boolVal, actual.ptr()->boolVal); \ } +#define EXPECT_UIA_DOUBLE_ARRAY_EQ(node, array_property_id, \ + expected_property_values) \ + { \ + ScopedVariant array; \ + ASSERT_HRESULT_SUCCEEDED( \ + node->GetPropertyValue(array_property_id, array.Receive())); \ + ASSERT_EQ(VT_ARRAY | VT_R8, array.type()); \ + ASSERT_EQ(1u, SafeArrayGetDim(array.ptr()->parray)); \ + LONG array_lower_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetLBound(array.ptr()->parray, 1, &array_lower_bound)); \ + LONG array_upper_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetUBound(array.ptr()->parray, 1, &array_upper_bound)); \ + double* array_data; \ + ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData( \ + array.ptr()->parray, reinterpret_cast<void**>(&array_data))); \ + size_t count = array_upper_bound - array_lower_bound + 1; \ + ASSERT_EQ(expected_property_values.size(), count); \ + for (size_t i = 0; i < count; ++i) { \ + EXPECT_EQ(array_data[i], expected_property_values[i]); \ + } \ + ASSERT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(array.ptr()->parray)); \ + } + #define EXPECT_UIA_INT_EQ(node, property_id, expected) \ { \ ScopedVariant expectedVariant(expected, VT_I4); \ @@ -158,6 +184,7 @@ // Destroy the tree and make sure we're not leaking any objects. ax_fragment_root_.reset(nullptr); tree_.reset(nullptr); + AXNodePosition::SetTreeForTesting(nullptr); ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting()); } @@ -3223,6 +3250,49 @@ EXPECT_UIA_INT_EQ(child_node1, UIA_PositionInSetPropertyId, 1); } +TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueClickablePoint) { + AXNodeData root; + root.id = 0; + root.role = ax::mojom::Role::kButton; + root.relative_bounds.bounds = gfx::RectF(20, 30, 100, 200); + Init(root); + + ComPtr<IRawElementProviderSimple> raw_element_provider_simple = + GetRootIRawElementProviderSimple(); + + // The clickable point of a rectangle {20, 30, 100, 200} is the rectangle's + // center, with coordinates {x: 70, y: 130}. + std::vector<double> expected_values = {70, 130}; + EXPECT_UIA_DOUBLE_ARRAY_EQ(raw_element_provider_simple, + UIA_ClickablePointPropertyId, expected_values); +} + +TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValue_Histogram) { + AXNodeData root; + root.id = 0; + Init(root); + ComPtr<IRawElementProviderSimple> root_node = + GetRootIRawElementProviderSimple(); + + // Log a known property ID + { + base::HistogramTester histogram_tester; + ScopedVariant property_value; + root_node->GetPropertyValue(UIA_NamePropertyId, property_value.Receive()); + histogram_tester.ExpectUniqueSample( + "Accessibility.WinAPIs.GetPropertyValue", UIA_NamePropertyId, 1); + } + + // Collapse unknown property IDs to zero + { + base::HistogramTester histogram_tester; + ScopedVariant property_value; + root_node->GetPropertyValue(42, property_value.Receive()); + histogram_tester.ExpectUniqueSample( + "Accessibility.WinAPIs.GetPropertyValue", 0, 1); + } +} + TEST_F(AXPlatformNodeWinTest, TestUIAGetDescribedByPropertyId) { AXNodeData root; std::vector<int32_t> describedby_ids = {1, 2, 3}; @@ -4187,7 +4257,8 @@ Init(root, text_field_with_combo_box, table, table_cell, meter, group_with_scroll, grid, checkbox); - EXPECT_EQ(PatternSet({UIA_ScrollItemPatternId, UIA_ValuePatternId}), + EXPECT_EQ(PatternSet({UIA_ScrollItemPatternId, UIA_ValuePatternId, + UIA_TextEditPatternId, UIA_TextPatternId}), GetSupportedPatternsFromNodeId(root_id)); EXPECT_EQ(PatternSet({UIA_ScrollItemPatternId, UIA_ValuePatternId,
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.h b/ui/accessibility/platform/ax_platform_node_win_unittest.h index 7220828..c4d929e 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.h +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.h
@@ -9,6 +9,8 @@ #include <unordered_set> +#include "ui/base/win/accessibility_misc_utils.h" + struct IAccessible; struct IAccessible2; struct IAccessible2_2;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index 9b9ee6ca..c410b5a 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -88,6 +88,13 @@ return tree_->data(); } +AXNodePosition::AXPositionInstance TestAXNodeWrapper::CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity) const { + return ui::AXNodePosition::CreateTextPosition(GetTreeData().tree_id, + node_->id(), offset, affinity); +} + gfx::NativeViewAccessible TestAXNodeWrapper::GetParent() { TestAXNodeWrapper* parent_wrapper = GetOrCreate(tree_, node_->parent()); return parent_wrapper ?
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h index 62ade134..0fea6a3d 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -44,6 +44,10 @@ // AXPlatformNodeDelegate. const AXNodeData& GetData() const override; const AXTreeData& GetTreeData() const override; + AXNodePosition::AXPositionInstance CreateTextPositionAt( + int offset, + ax::mojom::TextAffinity affinity = + ax::mojom::TextAffinity::kDownstream) const override; gfx::NativeViewAccessible GetParent() override; int GetChildCount() override; gfx::NativeViewAccessible ChildAtIndex(int index) override;
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc index 82c97a31..6020195 100644 --- a/ui/android/delegated_frame_host_android.cc +++ b/ui/android/delegated_frame_host_android.cc
@@ -196,7 +196,7 @@ content_layer_->RemoveFromParent(); content_layer_ = nullptr; } - if (!HasSavedFrame() || frame_evictor_->visible()) + if (!HasSavedFrame()) return; std::vector<viz::SurfaceId> surface_ids = { viz::SurfaceId(frame_sink_id_, local_surface_id_)};
diff --git a/ui/android/delegated_frame_host_android_unittest.cc b/ui/android/delegated_frame_host_android_unittest.cc index 2736d64..ad53248 100644 --- a/ui/android/delegated_frame_host_android_unittest.cc +++ b/ui/android/delegated_frame_host_android_unittest.cc
@@ -367,15 +367,16 @@ // Make sure frame evictor is notified of the newly embedded surface after // WasShown. TEST_F(DelegatedFrameHostAndroidVizTest, EmbedWhileHidden) { - // Ensure there is currently no frame. - frame_host_->WasHidden(); - frame_host_->EvictDelegatedFrame(); + { + EXPECT_CALL(client_, WasEvicted()); + frame_host_->EvictDelegatedFrame(); + } EXPECT_FALSE(frame_host_->HasSavedFrame()); - allocator_.GenerateId(); viz::LocalSurfaceId id = allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(); gfx::Size size(100, 100); + frame_host_->WasHidden(); frame_host_->EmbedSurface(id, size, cc::DeadlinePolicy::UseDefaultDeadline()); EXPECT_FALSE(frame_host_->HasSavedFrame()); frame_host_->WasShown(id, size);
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java index bb69ee0e..cce3db0a 100644 --- a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java +++ b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java
@@ -36,7 +36,7 @@ } private final Context mContext; - private final List<Pair<Integer, PropertyModel>> mSuggestionItems = new ArrayList<>(); + private final List<Pair<Integer, PropertyModel>> mModelList = new ArrayList<>(); private final SparseArray<Pair<ViewBuilder, PropertyModelChangeProcessor.ViewBinder>> mViewBuilderMap = new SparseArray<>(); @@ -45,22 +45,22 @@ } /** - * Update the visible omnibox suggestions. + * Update the visible models (list items). */ - public void updateSuggestions(List<Pair<Integer, PropertyModel>> suggestionModels) { - mSuggestionItems.clear(); - mSuggestionItems.addAll(suggestionModels); + public void updateModels(List<Pair<Integer, PropertyModel>> models) { + mModelList.clear(); + mModelList.addAll(models); notifyDataSetChanged(); } @Override public int getCount() { - return mSuggestionItems.size(); + return mModelList.size(); } @Override public Object getItem(int position) { - return mSuggestionItems.get(position); + return mModelList.get(position); } @Override @@ -83,7 +83,7 @@ @Override public int getItemViewType(int position) { - return mSuggestionItems.get(position).first; + return mModelList.get(position).first; } @Override @@ -96,33 +96,33 @@ public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null || convertView.getTag(R.id.view_type) == null || (int) convertView.getTag(R.id.view_type) != getItemViewType(position)) { - int suggestionTypeId = mSuggestionItems.get(position).first; - convertView = mViewBuilderMap.get(suggestionTypeId).first.buildView(); + int modelTypeId = mModelList.get(position).first; + convertView = mViewBuilderMap.get(modelTypeId).first.buildView(); // Since the view type returned by getView is not guaranteed to return a view of that // type, we need a means of checking it. The "view_type" tag is attached to the views // and identify what type the view is. This should allow lists that aren't necessarily // recycler views to work correctly with heterogeneous lists. - convertView.setTag(R.id.view_type, suggestionTypeId); + convertView.setTag(R.id.view_type, modelTypeId); } - PropertyModel suggestionModel = mSuggestionItems.get(position).second; + PropertyModel model = mModelList.get(position).second; PropertyModel viewModel = - getOrCreateModelFromExisting(convertView, mSuggestionItems.get(position)); - for (PropertyKey key : suggestionModel.getAllSetProperties()) { + getOrCreateModelFromExisting(convertView, mModelList.get(position)); + for (PropertyKey key : model.getAllSetProperties()) { if (key instanceof WritableIntPropertyKey) { WritableIntPropertyKey intKey = (WritableIntPropertyKey) key; - viewModel.set(intKey, suggestionModel.get(intKey)); + viewModel.set(intKey, model.get(intKey)); } else if (key instanceof WritableBooleanPropertyKey) { WritableBooleanPropertyKey booleanKey = (WritableBooleanPropertyKey) key; - viewModel.set(booleanKey, suggestionModel.get(booleanKey)); + viewModel.set(booleanKey, model.get(booleanKey)); } else if (key instanceof WritableFloatPropertyKey) { WritableFloatPropertyKey floatKey = (WritableFloatPropertyKey) key; - viewModel.set(floatKey, suggestionModel.get(floatKey)); + viewModel.set(floatKey, model.get(floatKey)); } else if (key instanceof WritableObjectPropertyKey<?>) { @SuppressWarnings({"unchecked", "rawtypes"}) WritableObjectPropertyKey objectKey = (WritableObjectPropertyKey) key; - viewModel.set(objectKey, suggestionModel.get(objectKey)); + viewModel.set(objectKey, model.get(objectKey)); } else { assert false : "Unexpected key received"; }
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc index 9a7c3b3e..9182c6b 100644 --- a/ui/aura/client/aura_constants.cc +++ b/ui/aura/client/aura_constants.cc
@@ -44,6 +44,8 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAlwaysOnTopKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAnimationsDisabledKey, false) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAppIconKey, nullptr) +DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAppIconLargeKey, nullptr) +DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAppIconSmallKey, nullptr) DEFINE_UI_CLASS_PROPERTY_KEY(int, kAppType, 0) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::SizeF, kAspectRatio, nullptr) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAvatarIconKey, nullptr)
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h index ca4b6c26..f3acf3f 100644 --- a/ui/aura/client/aura_constants.h +++ b/ui/aura/client/aura_constants.h
@@ -49,8 +49,19 @@ AURA_EXPORT extern const WindowProperty<bool>* const kAnimationsDisabledKey; // A property key to store the app icon, typically larger for shelf icons, etc. +// This is not transported to the window service. AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kAppIconKey; +// A property key to store a large version of the app icon, which is +// transported to the window service. +AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const + kAppIconLargeKey; + +// A property key to store a smaller version of the app icon, which is +// transported to the window service. +AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const + kAppIconSmallKey; + // A property key to store the type of window that will be used to record // pointer metrics. See AppType in ash/public/cpp/app_types.h for more details. AURA_EXPORT extern const WindowProperty<int>* const kAppType;
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc index 70727eca..dd9cd90 100644 --- a/ui/aura/mus/property_converter.cc +++ b/ui/aura/mus/property_converter.cc
@@ -72,10 +72,10 @@ PropertyConverter::PropertyConverter() { // Add known aura properties with associated mus properties. - RegisterImageSkiaProperty(client::kAppIconKey, - ws::mojom::WindowManager::kAppIcon_Property); - RegisterImageSkiaProperty(client::kWindowIconKey, - ws::mojom::WindowManager::kWindowIcon_Property); + RegisterImageSkiaProperty(client::kAppIconLargeKey, + ws::mojom::WindowManager::kAppIconLarge_Property); + RegisterImageSkiaProperty(client::kAppIconSmallKey, + ws::mojom::WindowManager::kAppIconSmall_Property); RegisterPrimitiveProperty(client::kAlwaysOnTopKey, ws::mojom::WindowManager::kAlwaysOnTop_Property, CreateAcceptAnyValueCallback());
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc index 3206b5a..a06c87c 100644 --- a/ui/aura/mus/window_tree_host_mus.cc +++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -202,7 +202,7 @@ const gfx::Rect pixel_bounds( gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), dsf), gfx::ScaleToCeiledSize(bounds_in_dip.size(), dsf)); - if (!in_set_bounds_from_server_) { + if (!is_server_setting_bounds_) { // Update the LocalSurfaceIdAllocation here, rather than in WindowTreeHost // as WindowTreeClient (the delegate) needs that information before // OnWindowTreeHostBoundsWillChange(). @@ -223,7 +223,7 @@ void WindowTreeHostMus::SetBoundsFromServer( const gfx::Rect& bounds, const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) { - base::AutoReset<bool> resetter(&in_set_bounds_from_server_, true); + base::AutoReset<bool> resetter(&is_server_setting_bounds_, true); SetBounds(bounds, local_surface_id_allocation); }
diff --git a/ui/aura/mus/window_tree_host_mus.h b/ui/aura/mus/window_tree_host_mus.h index 0d96a6a..45cdbf0 100644 --- a/ui/aura/mus/window_tree_host_mus.h +++ b/ui/aura/mus/window_tree_host_mus.h
@@ -127,7 +127,7 @@ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation = viz::LocalSurfaceIdAllocation()) override; - bool in_set_bounds_from_server() const { return in_set_bounds_from_server_; } + bool is_server_setting_bounds() const { return is_server_setting_bounds_; } private: int64_t display_id_; @@ -135,7 +135,7 @@ WindowTreeHostMusDelegate* delegate_; // If true, the server initiated the bounds change. - bool in_set_bounds_from_server_ = false; + bool is_server_setting_bounds_ = false; std::unique_ptr<InputMethodMus> input_method_;
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc index ea4ba92..69a8aeb2 100644 --- a/ui/chromeos/events/event_rewriter_chromeos.cc +++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -285,6 +285,30 @@ } // namespace +/////////////////////////////////////////////////////////////////////////////// + +EventRewriterChromeOS::MutableKeyState::MutableKeyState() + : MutableKeyState(0, ui::DomCode::NONE, 0, ui::KeyboardCode::VKEY_NONAME) {} + +EventRewriterChromeOS::MutableKeyState::MutableKeyState( + const ui::KeyEvent* key_event) + : MutableKeyState(key_event->flags(), + key_event->code(), + key_event->GetDomKey(), + key_event->key_code()) {} + +EventRewriterChromeOS::MutableKeyState::MutableKeyState( + int input_flags, + ui::DomCode input_code, + ui::DomKey::Base input_key, + ui::KeyboardCode input_key_code) + : flags(input_flags), + code(input_code), + key(input_key), + key_code(input_key_code) {} + +/////////////////////////////////////////////////////////////////////////////// + EventRewriterChromeOS::EventRewriterChromeOS( Delegate* delegate, ui::EventRewriter* sticky_keys_controller) @@ -365,8 +389,11 @@ std::unique_ptr<ui::Event>* rewritten_event) { if ((event.type() == ui::ET_KEY_PRESSED) || (event.type() == ui::ET_KEY_RELEASED)) { - return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event), - rewritten_event); + ui::EventRewriteStatus status = + RewriteKeyEvent(*((&event)->AsKeyEvent()), rewritten_event); + RewriteKeyEventInContext(*((&event)->AsKeyEvent()), rewritten_event, + &status); + return status; } if ((event.type() == ui::ET_MOUSE_PRESSED) || (event.type() == ui::ET_MOUSE_RELEASED)) { @@ -392,6 +419,15 @@ ui::EventRewriteStatus EventRewriterChromeOS::NextDispatchEvent( const ui::Event& last_event, std::unique_ptr<ui::Event>* new_event) { + if (dispatched_key_events_.size()) { + *new_event = std::move(dispatched_key_events_.back()); + dispatched_key_events_.pop_back(); + + if (dispatched_key_events_.size()) + return ui::EVENT_REWRITE_DISPATCH_ANOTHER; + return ui::EVENT_REWRITE_REWRITTEN; + } + if (sticky_keys_controller_) { // In the case of sticky keys, we know what the events obtained here are: // modifier key releases that match the ones previously discarded. So, we @@ -1220,6 +1256,123 @@ return ui::EF_NONE; } +void EventRewriterChromeOS::RewriteKeyEventInContext( + const ui::KeyEvent& key_event, + std::unique_ptr<ui::Event>* rewritten_event, + ui::EventRewriteStatus* status) { + DCHECK(status); + + if (*status == EventRewriteStatus::EVENT_REWRITE_DISCARD) + return; + + MutableKeyState current_key_state; + auto key_state_comparator = + [¤t_key_state]( + const std::pair<MutableKeyState, MutableKeyState>& key_state) { + return (current_key_state.code == key_state.first.code) && + (current_key_state.key == key_state.first.key) && + (current_key_state.key_code == key_state.first.key_code); + }; + + const int mapped_flag = ModifierDomKeyToEventFlag(key_event.GetDomKey()); + + if (key_event.type() == ET_KEY_PRESSED) { + current_key_state = MutableKeyState( + rewritten_event->get() + ? static_cast<const ui::KeyEvent*>(rewritten_event->get()) + : &key_event); + MutableKeyState original_key_state(&key_event); + auto iter = std::find_if(pressed_key_states_.begin(), + pressed_key_states_.end(), key_state_comparator); + + // When a key is pressed, store |current_key_state| if it is not stored + // before. + if (iter == pressed_key_states_.end()) { + pressed_key_states_.push_back( + std::make_pair(current_key_state, original_key_state)); + } + + return; + } + + DCHECK_EQ(key_event.type(), ET_KEY_RELEASED); + + if (mapped_flag != EF_NONE) { + // The released key is a modifier + + DomKey::Base current_key = key_event.GetDomKey(); + auto key_state_iter = pressed_key_states_.begin(); + int event_flags = rewritten_event->get() ? (*rewritten_event)->flags() + : key_event.flags(); + rewritten_event->reset(); + + // Iterate the keys being pressed. Release the key events which satisfy one + // of the following conditions: + // (1) the key event's original key code (before key event rewriting if + // any) is the same with the key to be released. + // (2) the key event is rewritten and its original flags are influenced by + // the key to be released. + // Example: Press the Launcher button, Press the Up Arrow button, Release + // the Launcher button. When Launcher is released: the key event whose key + // code is Launcher should be released because it satisfies the condition 1; + // the key event whose key code is PageUp should be released because it + // satisfies the condition 2. + while (key_state_iter != pressed_key_states_.end()) { + const bool is_rewritten = + (key_state_iter->first.key != key_state_iter->second.key); + const bool flag_affected = key_state_iter->second.flags & mapped_flag; + const bool should_release = key_state_iter->second.key == current_key || + (flag_affected && is_rewritten); + + if (should_release) { + // If the key should be released, create a key event for it. + std::unique_ptr<ui::KeyEvent> dispatched_event = + std::make_unique<ui::KeyEvent>( + key_event.type(), key_state_iter->first.key_code, + key_state_iter->first.code, event_flags, + key_state_iter->first.key, key_event.time_stamp()); + if (!rewritten_event->get()) + *rewritten_event = std::move(dispatched_event); + else + dispatched_key_events_.push_back(std::move(dispatched_event)); + + key_state_iter = pressed_key_states_.erase(key_state_iter); + continue; + } + key_state_iter++; + } + + if (dispatched_key_events_.empty()) { + *status = rewritten_event->get() + ? EventRewriteStatus::EVENT_REWRITE_REWRITTEN + : EventRewriteStatus::EVENT_REWRITE_DISCARD; + } else { + *status = EventRewriteStatus::EVENT_REWRITE_DISPATCH_ANOTHER; + } + } else { + // The released key is not a modifier + + current_key_state = MutableKeyState( + rewritten_event->get() + ? static_cast<const ui::KeyEvent*>(rewritten_event->get()) + : &key_event); + auto iter = std::find_if(pressed_key_states_.begin(), + pressed_key_states_.end(), key_state_comparator); + if (iter != pressed_key_states_.end()) { + pressed_key_states_.erase(iter); + } else { + // Event rewriting may create a meaningless key event. + // For example: press the Up Arrow button, press the Launcher button, + // release the Up Arrow. When the Up Arrow button is released, key event + // rewriting happens. However, the rewritten event is not among + // |pressed_key_states_|. So it should be blocked and the original event + // should be propagated. + rewritten_event->reset(); + *status = EventRewriteStatus::EVENT_REWRITE_CONTINUE; + } + } +} + void EventRewriterChromeOS::KeyboardDeviceAddedInternal( int device_id, DeviceType type,
diff --git a/ui/chromeos/events/event_rewriter_chromeos.h b/ui/chromeos/events/event_rewriter_chromeos.h index f33ab8c..ca389643 100644 --- a/ui/chromeos/events/event_rewriter_chromeos.h +++ b/ui/chromeos/events/event_rewriter_chromeos.h
@@ -5,10 +5,13 @@ #ifndef UI_CHROMEOS_EVENTS_EVENT_REWRITER_CHROMEOS_H_ #define UI_CHROMEOS_EVENTS_EVENT_REWRITER_CHROMEOS_H_ +#include <list> #include <map> #include <memory> #include <set> #include <string> +#include <utility> +#include <vector> #include "base/files/file_path.h" #include "base/macros.h" @@ -64,6 +67,13 @@ // Things that keyboard-related rewriter phases can change about an Event. struct MutableKeyState { + MutableKeyState(); + explicit MutableKeyState(const ui::KeyEvent* key_event); + MutableKeyState(int input_flags, + ui::DomCode input_code, + ui::DomKey::Base input_key, + ui::KeyboardCode input_key_code); + int flags; ui::DomCode code; ui::DomKey::Base key; @@ -215,6 +225,13 @@ void RewriteLocatedEvent(const ui::Event& event, int* flags); int RewriteModifierClick(const ui::MouseEvent& event, int* flags); + // Take the keys being pressed into consideration, in contrast to + // RewriteKeyEvent which computes the rewritten event and event rewrite status + // in stateless way. + void RewriteKeyEventInContext(const ui::KeyEvent& event, + std::unique_ptr<ui::Event>* rewritten_event, + ui::EventRewriteStatus* status); + // A set of device IDs whose press event has been rewritten. // This is to ensure that press and release events are rewritten consistently. std::set<int> pressed_device_ids_; @@ -229,6 +246,14 @@ Delegate* const delegate_; + // For each pair, the first element is the rewritten key state and the second + // one is the original key state. If no key event rewriting happens, the first + // element and the second element are identical. + std::list<std::pair<MutableKeyState, MutableKeyState>> pressed_key_states_; + + // Store key events when there are more than one key events to be dispatched. + std::vector<std::unique_ptr<ui::KeyEvent>> dispatched_key_events_; + // The sticky keys controller is not owned here; // at time of writing it is a singleton in ash::Shell. ui::EventRewriter* const sticky_keys_controller_;
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index 9a35b6a1..231d93b 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -261,6 +261,14 @@ std::unique_ptr<EventWithCallback> event_with_callback, const base::TimeTicks now) { ui::LatencyInfo monitored_latency_info = event_with_callback->latency_info(); + + if (event_with_callback->event().GetType() == + WebInputEvent::kGestureScrollUpdate) { + monitored_latency_info.set_scroll_update_delta( + static_cast<const WebGestureEvent&>(event_with_callback->event()) + .data.scroll_update.delta_y); + } + std::unique_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor = input_handler_->CreateLatencyInfoSwapPromiseMonitor( &monitored_latency_info);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index 75a2795e..edabb33 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -1916,6 +1916,67 @@ testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); } +TEST_F(InputHandlerProxyEventQueueTest, LatencyInfoScrollUpdateDelta) { + // Scroll on compositor. + cc::InputHandlerScrollResult scroll_result_did_scroll_; + scroll_result_did_scroll_.did_scroll = true; + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kImplThreadScrollState)); + EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1); + EXPECT_CALL( + mock_input_handler_, + ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)))) + .WillOnce(testing::Return(scroll_result_did_scroll_)); + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + + HandleGestureEvent(WebInputEvent::kGestureScrollBegin); + HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20); + HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -40); + HandleGestureEvent(WebInputEvent::kGestureScrollEnd); + input_handler_proxy_->DeliverInputForBeginFrame(); + + EXPECT_EQ(0ul, event_queue().size()); + // Should run callbacks for every original events. + EXPECT_EQ(4ul, event_disposition_recorder_.size()); + EXPECT_EQ(4ul, latency_info_recorder_.size()); + EXPECT_EQ(false, latency_info_recorder_[1].coalesced()); + EXPECT_EQ(-60, latency_info_recorder_[1].scroll_update_delta()); + + EXPECT_EQ(true, latency_info_recorder_[2].coalesced()); + EXPECT_EQ(-60, latency_info_recorder_[2].scroll_update_delta()); + + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); + + latency_info_recorder_.clear(); + + // Scroll on main thread. + cc::InputHandlerScrollResult scroll_result_did_not_scroll_; + scroll_result_did_not_scroll_.did_scroll = false; + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kMainThreadScrollState)); + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + + HandleGestureEvent(WebInputEvent::kGestureScrollBegin); + HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20); + HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -40); + HandleGestureEvent(WebInputEvent::kGestureScrollEnd); + input_handler_proxy_->DeliverInputForBeginFrame(); + + EXPECT_EQ(0ul, event_queue().size()); + // Should run callbacks for every original events. + EXPECT_EQ(8ul, event_disposition_recorder_.size()); + EXPECT_EQ(4ul, latency_info_recorder_.size()); + + EXPECT_EQ(false, latency_info_recorder_[1].coalesced()); + EXPECT_EQ(-20, latency_info_recorder_[1].scroll_update_delta()); + + EXPECT_EQ(false, latency_info_recorder_[2].coalesced()); + EXPECT_EQ(-40, latency_info_recorder_[2].scroll_update_delta()); + + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); +} + class InputHandlerProxyMainThreadScrollingReasonTest : public InputHandlerProxyTest { public:
diff --git a/ui/events/keycodes/keyboard_code_conversion.cc b/ui/events/keycodes/keyboard_code_conversion.cc index 45a6999..c1f48404 100644 --- a/ui/events/keycodes/keyboard_code_conversion.cc +++ b/ui/events/keycodes/keyboard_code_conversion.cc
@@ -263,4 +263,34 @@ DomCodeToUsLayoutKeyboardCode(dom_code)); } +int ModifierDomKeyToEventFlag(DomKey key) { + switch (key) { + case DomKey::ALT: + return EF_ALT_DOWN; + case DomKey::ALT_GRAPH: + return EF_ALTGR_DOWN; + case DomKey::CAPS_LOCK: + return EF_CAPS_LOCK_ON; + case DomKey::CONTROL: + return EF_CONTROL_DOWN; + case DomKey::META: + return EF_COMMAND_DOWN; + case DomKey::SHIFT: + return EF_SHIFT_DOWN; + case DomKey::SHIFT_LEVEL5: + return EF_MOD3_DOWN; + default: + return EF_NONE; + } + // Not represented: + // DomKey::ACCEL + // DomKey::FN + // DomKey::FN_LOCK + // DomKey::HYPER + // DomKey::NUM_LOCK + // DomKey::SCROLL_LOCK + // DomKey::SUPER + // DomKey::SYMBOL_LOCK +} + } // namespace ui
diff --git a/ui/events/keycodes/keyboard_code_conversion.h b/ui/events/keycodes/keyboard_code_conversion.h index d3c035ce..3450f520 100644 --- a/ui/events/keycodes/keyboard_code_conversion.h +++ b/ui/events/keycodes/keyboard_code_conversion.h
@@ -107,6 +107,10 @@ EVENTS_BASE_EXPORT KeyboardCode DomCodeToUsLayoutNonLocatedKeyboardCode(DomCode dom_code); +// Returns the ui::EventFlags value associated with a modifier key, +// or 0 (EF_NONE) if the key is not a modifier. +EVENTS_BASE_EXPORT int ModifierDomKeyToEventFlag(DomKey key); + } // namespace ui #endif // UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_H_
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn index 48f7ad99..d1c8e6c 100644 --- a/ui/events/ozone/BUILD.gn +++ b/ui/events/ozone/BUILD.gn
@@ -188,8 +188,6 @@ "layout/keyboard_layout_engine.h", "layout/keyboard_layout_engine_manager.cc", "layout/keyboard_layout_engine_manager.h", - "layout/layout_util.cc", - "layout/layout_util.h", "layout/no/no_keyboard_layout_engine.cc", "layout/no/no_keyboard_layout_engine.h", "layout/stub/stub_keyboard_layout_engine.cc",
diff --git a/ui/events/ozone/evdev/keyboard_evdev.cc b/ui/events/ozone/evdev/keyboard_evdev.cc index a0f5420..a4ba3f5 100644 --- a/ui/events/ozone/evdev/keyboard_evdev.cc +++ b/ui/events/ozone/evdev/keyboard_evdev.cc
@@ -12,10 +12,10 @@ #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" #include "ui/events/ozone/evdev/keyboard_util_evdev.h" #include "ui/events/ozone/layout/keyboard_layout_engine.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" -#include "ui/events/ozone/layout/layout_util.h" namespace ui {
diff --git a/ui/events/ozone/layout/layout_util.cc b/ui/events/ozone/layout/layout_util.cc deleted file mode 100644 index eaafb10e..0000000 --- a/ui/events/ozone/layout/layout_util.cc +++ /dev/null
@@ -1,42 +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 "ui/events/ozone/layout/layout_util.h" - -#include "ui/events/event_constants.h" -#include "ui/events/keycodes/dom/dom_key.h" - -namespace ui { - -int ModifierDomKeyToEventFlag(DomKey key) { - switch (key) { - case DomKey::ALT: - return EF_ALT_DOWN; - case DomKey::ALT_GRAPH: - return EF_ALTGR_DOWN; - case DomKey::CAPS_LOCK: - return EF_CAPS_LOCK_ON; - case DomKey::CONTROL: - return EF_CONTROL_DOWN; - case DomKey::META: - return EF_COMMAND_DOWN; - case DomKey::SHIFT: - return EF_SHIFT_DOWN; - case DomKey::SHIFT_LEVEL5: - return EF_MOD3_DOWN; - default: - return EF_NONE; - } - // Not represented: - // DomKey::ACCEL - // DomKey::FN - // DomKey::FN_LOCK - // DomKey::HYPER - // DomKey::NUM_LOCK - // DomKey::SCROLL_LOCK - // DomKey::SUPER - // DomKey::SYMBOL_LOCK -} - -} // namespace ui
diff --git a/ui/events/ozone/layout/layout_util.h b/ui/events/ozone/layout/layout_util.h deleted file mode 100644 index 5a2ba52..0000000 --- a/ui/events/ozone/layout/layout_util.h +++ /dev/null
@@ -1,23 +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 UI_EVENTS_OZONE_LAYOUT_LAYOUT_UTIL_H_ -#define UI_EVENTS_OZONE_LAYOUT_LAYOUT_UTIL_H_ - -// TODO(kpschoedel): consider moving this out of Ozone. - -#include "base/strings/string16.h" -#include "ui/events/keycodes/dom/dom_key.h" -#include "ui/events/keycodes/keyboard_codes.h" -#include "ui/events/ozone/layout/events_ozone_layout_export.h" - -namespace ui { - -// Returns the ui::EventFlags value associated with a modifier key, -// or 0 (EF_NONE) if the key is not a modifier. -EVENTS_OZONE_LAYOUT_EXPORT int ModifierDomKeyToEventFlag(DomKey key); - -} // namespace ui - -#endif // UI_EVENTS_OZONE_LAYOUT_LAYOUT_UTIL_H_
diff --git a/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc b/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc index 090f95158..7ca33e2 100644 --- a/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc +++ b/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc
@@ -8,7 +8,6 @@ #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/dom_key.h" #include "ui/events/keycodes/keyboard_code_conversion.h" -#include "ui/events/ozone/layout/layout_util.h" namespace ui {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 7e8a26f..90577c4ae 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -836,6 +836,11 @@ icon.classList.add('item-icon'); icon.setAttribute('root-type-icon', rootType); + // MyFiles shows expanded by default. + if (rootType === VolumeManagerCommon.RootType.MY_FILES) { + item.mayHaveChildren_ = true; + item.expanded = true; + } // Populate children of this volume. item.updateSubDirectories(false /* recursive */); @@ -918,9 +923,6 @@ const onSuccess = (entries) => { this.entries_ = entries; this.updateSubElementsFromList(recursive); - if (this.entries_.length > 0) { - this.expanded = true; - } opt_successCallback && opt_successCallback(); }; const reader = this.entry.createReader();
diff --git a/ui/file_manager/integration_tests/file_manager/background.js b/ui/file_manager/integration_tests/file_manager/background.js index 1fc3e3e..2b0c51cc 100644 --- a/ui/file_manager/integration_tests/file_manager/background.js +++ b/ui/file_manager/integration_tests/file_manager/background.js
@@ -271,7 +271,7 @@ * @param {?string} initialRoot Root path to be used as a default current * directory during initialization. Can be null, for no default path. * @param {!Array<TestEntryInfo>>} initialLocalEntries List of initial - * entries to load in Google Drive (defaults to a basic entry set). + * entries to load in Downloads (defaults to a basic entry set). * @param {!Array<TestEntryInfo>>} initialDriveEntries List of initial * entries to load in Google Drive (defaults to a basic entry set). * @param {Object} appState App state to be passed with on opening the Files @@ -469,3 +469,26 @@ const expandedSubtree = treeItem + '> .tree-children[expanded]'; await remoteCall.waitForElement(appId, expandedSubtree); } + +/** + * Mounts crostini volume by clicking on the fake crostini root. + * @param {string} appId Files app windowId. + * @param {!Array<TestEntryInfo>>} initialEntries List of initial entries to + * load in Crostini (defaults to a basic entry set). + */ +async function mountCrostini(appId, initialEntries = BASIC_CROSTINI_ENTRY_SET) { + const fakeLinuxFiles = '#directory-tree [root-type-icon="crostini"]'; + const realLinxuFiles = '#directory-tree [volume-type-icon="crostini"]'; + + // Add entries to crostini volume, but do not mount. + await addEntries(['crostini'], initialEntries); + + // Linux files fake root is shown. + await remoteCall.waitForElement(appId, fakeLinuxFiles); + + // Mount crostini, and ensure real root and files are shown. + remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [fakeLinuxFiles]); + await remoteCall.waitForElement(appId, realLinxuFiles); + const files = TestEntryInfo.getExpectedRows(BASIC_CROSTINI_ENTRY_SET); + await remoteCall.waitForFiles(appId, files); +}
diff --git a/ui/file_manager/integration_tests/file_manager/crostini.js b/ui/file_manager/integration_tests/file_manager/crostini.js index f53d97b..ed0889ba 100644 --- a/ui/file_manager/integration_tests/file_manager/crostini.js +++ b/ui/file_manager/integration_tests/file_manager/crostini.js
@@ -10,17 +10,7 @@ const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []); - // Add entries to crostini volume, but do not mount. - await addEntries(['crostini'], BASIC_CROSTINI_ENTRY_SET); - - // Linux files fake root is shown. - await remoteCall.waitForElement(appId, fakeLinuxFiles); - - // Mount crostini, and ensure real root and files are shown. - remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [fakeLinuxFiles]); - await remoteCall.waitForElement(appId, realLinxuFiles); - const files = TestEntryInfo.getExpectedRows(BASIC_CROSTINI_ENTRY_SET); - await remoteCall.waitForFiles(appId, files); + await mountCrostini(appId); // Unmount and ensure fake root is shown. remoteCall.callRemoteTestUtil('unmount', null, ['crostini']);
diff --git a/ui/file_manager/integration_tests/file_manager/metadata.js b/ui/file_manager/integration_tests/file_manager/metadata.js index 3618e06..b4a7bb0f 100644 --- a/ui/file_manager/integration_tests/file_manager/metadata.js +++ b/ui/file_manager/integration_tests/file_manager/metadata.js
@@ -121,7 +121,7 @@ // Navigate 2 folders deep, because navigating in directory tree might // trigger further metadata fetches. await remoteCall.navigateWithDirectoryTree( - appId, '/root/photos1/folder1', 'My Drive'); + appId, '/root/photos1/folder1', 'My Drive', 'drive'); // Fetch the metadata stats. const metadataStats = @@ -216,11 +216,12 @@ // Open Files app on Drive. const appId = await setupAndWaitUntilReady(RootPath.DRIVE, entries, entries); + console.log('setupAndWaitUntilReady finished!'); // Navigate only 1 folder deep,which is slightly different from // metadatatDrive test. await remoteCall.navigateWithDirectoryTree( - appId, '/root/folder1', 'My Drive'); + appId, '/root/folder1', 'My Drive', 'drive'); // Wait for the metadata stats to reach the desired count. // File list component, doesn't display all files at once for performance @@ -287,7 +288,7 @@ // Navigate to Team Drives root. await remoteCall.navigateWithDirectoryTree( - appId, '/team_drives', 'Team Drives'); + appId, '/team_drives', 'Team Drives', 'drive'); // Expand Team Drives, because expanding might need metadata. const expandIcon = teamDriveTreeItem + ' > .tree-row > .expand-icon';
diff --git a/ui/file_manager/integration_tests/file_manager/my_files.js b/ui/file_manager/integration_tests/file_manager/my_files.js index aab3fb6..3faf773f 100644 --- a/ui/file_manager/integration_tests/file_manager/my_files.js +++ b/ui/file_manager/integration_tests/file_manager/my_files.js
@@ -294,3 +294,41 @@ appId, expectedRows2, {ignoreFileSize: true, ignoreLastModifiedTime: true}); }; + +/** + * Tests that MyFiles only auto expands once. + */ +testcase.myFilesAutoExpandOnce = async () => { + // Open Files app on local Downloads. + const appId = await setupAndWaitUntilReady( + RootPath.DOWNLOADS, [ENTRIES.photos], [ENTRIES.beautiful]); + + // Collapse MyFiles. + const myFiles = '#directory-tree [entry-label="My files"]'; + let expandIcon = myFiles + '[expanded] > .tree-row[has-children=true]' + + '> .expand-icon'; + await remoteCall.waitAndClickElement(appId, expandIcon); + await remoteCall.waitForElement(appId, myFiles + ':not([expanded])'); + + // Expand Google Drive. + const driveGrandRoot = '#directory-tree [entry-label="Google Drive"]'; + expandIcon = driveGrandRoot + ' > .tree-row > .expand-icon'; + await remoteCall.waitAndClickElement(appId, expandIcon); + + // Wait for its subtree to expand and display its children. + const expandedSubItems = + driveGrandRoot + ' > .tree-children[expanded] > .tree-item'; + await remoteCall.waitForElement(appId, expandedSubItems); + + // Click on My Drive + const myDrive = '#directory-tree [entry-label="My Drive"]'; + await remoteCall.waitAndClickElement(appId, myDrive); + + // Wait for My Drive to selected. + await remoteCall.waitForFiles( + appId, [ENTRIES.beautiful.getExpectedRow()], + {ignoreFileSize: true, ignoreLastModifiedTime: true}); + + // Check that MyFiles is still collapsed. + await remoteCall.waitForElement(appId, myFiles + ':not([expanded])'); +};
diff --git a/ui/file_manager/integration_tests/file_manager/quick_view.js b/ui/file_manager/integration_tests/file_manager/quick_view.js index 651f5473..20a92515 100644 --- a/ui/file_manager/integration_tests/file_manager/quick_view.js +++ b/ui/file_manager/integration_tests/file_manager/quick_view.js
@@ -236,33 +236,12 @@ * Tests opening Quick View on a Crostini file. */ testcase.openQuickViewCrostini = async () => { - const fakeLinuxFiles = '#directory-tree [root-type-icon="crostini"]'; - const realLinuxFiles = '#directory-tree [volume-type-icon="crostini"]'; - // Open Files app on Downloads containing ENTRIES.photos. const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []); - // Check: the fake Linux files icon should be shown. - await remoteCall.waitForElement(appId, fakeLinuxFiles); - - // Add files to the Crostini volume. - await addEntries(['crostini'], BASIC_CROSTINI_ENTRY_SET); - - // Click the fake Linux files icon to mount the Crostini volume. - chrome.test.assertTrue( - !!await remoteCall.callRemoteTestUtil( - 'fakeMouseClick', appId, [fakeLinuxFiles]), - 'fakeMouseClick failed'); - - // Check: the Crostini volume icon should appear. - await remoteCall.waitForElement(appId, realLinuxFiles); - - // Check: the Crostini files should appear in the file list. - const files = TestEntryInfo.getExpectedRows(BASIC_CROSTINI_ENTRY_SET); - await remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true}); - // Open a Crostini file in Quick View. + await mountCrostini(appId); await openQuickView(appId, ENTRIES.hello.nameText); };
diff --git a/ui/file_manager/integration_tests/file_manager/recents.js b/ui/file_manager/integration_tests/file_manager/recents.js index 69c387cd..6c11f6c 100644 --- a/ui/file_manager/integration_tests/file_manager/recents.js +++ b/ui/file_manager/integration_tests/file_manager/recents.js
@@ -39,6 +39,24 @@ await verifyRecents(appId); }; +testcase.recentsCrostiniNotMounted = async () => { + // Add entries to crostini volume, but do not mount. + // The crostini entries should not show up in recents. + await addEntries(['crostini'], BASIC_CROSTINI_ENTRY_SET); + + const appId = await setupAndWaitUntilReady( + RootPath.DOWNLOADS, [ENTRIES.beautiful, ENTRIES.photos], []); + await verifyRecents(appId, [ENTRIES.beautiful]); +}; + +testcase.recentsCrostiniMounted = async () => { + const appId = await setupAndWaitUntilReady( + RootPath.DOWNLOADS, [ENTRIES.beautiful, ENTRIES.photos], []); + // Mount crostini and both downloads and crostini entries will be in recents. + await mountCrostini(appId); + await verifyRecents(appId); +}; + testcase.recentsDownloadsAndDrive = async () => { // Populate both downloads and drive with disjoint sets of files. const appId = await setupAndWaitUntilReady(
diff --git a/ui/gfx/geometry/mojo/geometry.typemap b/ui/gfx/geometry/mojo/geometry.typemap index f7939a8b..db70bf0 100644 --- a/ui/gfx/geometry/mojo/geometry.typemap +++ b/ui/gfx/geometry/mojo/geometry.typemap
@@ -18,7 +18,7 @@ "//ui/gfx/geometry/vector3d_f.h", ] traits_headers = [ "//ui/gfx/geometry/mojo/geometry_struct_traits.h" ] -deps = [ +public_deps = [ "//ui/gfx/geometry/mojo:struct_traits", ] type_mappings = [
diff --git a/ui/gl/init/create_gr_gl_interface.cc b/ui/gl/init/create_gr_gl_interface.cc index 7d3c3eb..bdba564 100644 --- a/ui/gl/init/create_gr_gl_interface.cc +++ b/ui/gl/init/create_gr_gl_interface.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ui/gl/init/create_gr_gl_interface.h" +#include "build/build_config.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/progress_reporter.h" @@ -40,6 +41,20 @@ }; } +template <typename R, typename... Args> +GrGLFunction<R GR_GL_FUNCTION_TYPE(Args...)> bind_with_flush_on_mac( + R(GL_BINDING_CALL* func)(Args...)) { +#if defined(OS_MACOSX) + return [func](Args... args) { + glFlush(); + func(args...); + glFlush(); + }; +#else + return func; +#endif +} + const GLubyte* GetStringHook(const char* version_string, GLenum name) { switch (name) { case GL_VERSION: @@ -300,7 +315,8 @@ gl->glGetFramebufferAttachmentParameterivEXTFn; functions->fGetRenderbufferParameteriv = gl->glGetRenderbufferParameterivEXTFn; - functions->fBindFramebuffer = gl->glBindFramebufferEXTFn; + functions->fBindFramebuffer = + bind_with_flush_on_mac(gl->glBindFramebufferEXTFn); functions->fFramebufferTexture2D = gl->glFramebufferTexture2DEXTFn; functions->fCheckFramebufferStatus = gl->glCheckFramebufferStatusEXTFn; functions->fDeleteFramebuffers =
diff --git a/ui/login/account_picker/chromeos_screen_account_picker.js b/ui/login/account_picker/chromeos_screen_account_picker.js index 931b0d8..5dd3af3 100644 --- a/ui/login/account_picker/chromeos_screen_account_picker.js +++ b/ui/login/account_picker/chromeos_screen_account_picker.js
@@ -25,10 +25,6 @@ return { EXTERNAL_API: [ 'loadUsers', - 'runAppForTesting', - 'setApps', - 'setShouldShowApps', - 'showAppError', 'updateUserImage', 'setCapsLockState', 'removeUser', @@ -123,9 +119,10 @@ this.showing_ = true; chrome.send('loginUIStateChanged', ['account-picker', true]); - $('login-header-bar').signinUIState = SIGNIN_UI_STATE.ACCOUNT_PICKER; + chrome.send('hideCaptivePortal'); var podRow = $('pod-row'); + podRow.signinUIState = SIGNIN_UI_STATE.ACCOUNT_PICKER; podRow.handleBeforeShow(); // In case of the preselected pod onShow will be called once pod @@ -165,8 +162,9 @@ $('bubble-persistent').hide(); this.showing_ = false; chrome.send('loginUIStateChanged', ['account-picker', false]); - $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN; - $('pod-row').handleHide(); + var podRow = $('pod-row'); + podRow.signinUIState = SIGNIN_UI_STATE.HIDDEN; + podRow.handleHide(); }, /** @@ -257,55 +255,9 @@ /** * Loads given users in pod row. * @param {array} users Array of user. - * @param {boolean} showGuest Whether to show guest session button. */ - loadUsers: function(users, showGuest) { + loadUsers: function(users) { $('pod-row').loadPods(users); - $('login-header-bar').showGuestButton = showGuest; - // On Desktop, #login-header-bar has a shadow if there are 8+ profiles. - if (Oobe.getInstance().displayType == DISPLAY_TYPE.DESKTOP_USER_MANAGER) - $('login-header-bar').classList.toggle('shadow', users.length > 8); - }, - - /** - * Runs app with a given id from the list of loaded apps. - * @param {!string} app_id of an app to run. - * @param {boolean=} opt_diagnostic_mode Whether to run the app in - * diagnostic mode. Default is false. - */ - runAppForTesting: function(app_id, opt_diagnostic_mode) { - $('pod-row').findAndRunAppForTesting(app_id, opt_diagnostic_mode); - }, - - /** - * Adds given apps to the pod row. - * @param {array} apps Array of apps. - */ - setApps: function(apps) { - $('pod-row').setApps(apps); - }, - - /** - * Sets the flag of whether app pods should be visible. - * @param {boolean} shouldShowApps Whether to show app pods. - */ - setShouldShowApps: function(shouldShowApps) { - $('pod-row').setShouldShowApps(shouldShowApps); - }, - - /** - * Shows the given kiosk app error message. - * @param {!string} message Error message to show. - */ - showAppError: function(message) { - // TODO(nkostylev): Figure out a way to show kiosk app launch error - // pointing to the kiosk app pod. - /** @const */ var BUBBLE_PADDING = 12; - $('bubble').showTextForElement($('pod-row'), - message, - cr.ui.Bubble.Attachment.BOTTOM, - $('pod-row').offsetWidth / 2, - BUBBLE_PADDING); }, /**
diff --git a/ui/login/account_picker/chromeos_user_pod_row.css b/ui/login/account_picker/chromeos_user_pod_row.css index 75a143df..88c4092c 100644 --- a/ui/login/account_picker/chromeos_user_pod_row.css +++ b/ui/login/account_picker/chromeos_user_pod_row.css
@@ -496,20 +496,6 @@ width: 27px; } -.launch-app-button-container { - display: block; - flex: auto; - text-align: center; -} - -.launch-app-button { - display: inline; - margin-top: 6px !important; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; -} - .pod[auth-type='onlineSignIn'] .reauth-hint-container { display: flex; justify-content: center;
diff --git a/ui/login/account_picker/chromeos_user_pod_row.js b/ui/login/account_picker/chromeos_user_pod_row.js index ef413054..9ae0957 100644 --- a/ui/login/account_picker/chromeos_user_pod_row.js +++ b/ui/login/account_picker/chromeos_user_pod_row.js
@@ -1088,22 +1088,6 @@ }, /** - * Gets the container holding the launch app button. - * @type {!HTMLButtonElement} - */ - get launchAppButtonContainerElement() { - return this.querySelector('.launch-app-button-container'); - }, - - /** - * Gets launch app button. - * @type {!HTMLButtonElement} - */ - get launchAppButtonElement() { - return this.querySelector('.launch-app-button'); - }, - - /** * Gets action box area. * @type {!HTMLInputElement} */ @@ -1289,7 +1273,7 @@ }, updateActionBoxArea: function() { - if (this.user_.publicAccount || this.user_.isApp) { + if (this.user_.publicAccount) { this.actionBoxAreaElement.hidden = true; return; } @@ -1326,8 +1310,6 @@ } else { this.querySelector('.mp-policy-not-allowed-msg').hidden = false; } - } else if (this.user_.isApp) { - this.setUserPodIconType('app'); } }, @@ -2906,115 +2888,6 @@ }; /** - * Creates a user pod that represents kiosk app. - * @constructor - * @extends {UserPod} - */ - var KioskAppPod = cr.ui.define(function() { - var node = UserPod(); - return node; - }); - - KioskAppPod.prototype = { - __proto__: UserPod.prototype, - - /** @override */ - decorate: function() { - UserPod.prototype.decorate.call(this); - this.launchAppButtonElement.addEventListener('click', - this.activate.bind(this)); - }, - - /** @override */ - update: function() { - this.imageElement.src = this.user.iconUrl; - this.imageElement.alt = this.user.label; - this.imageElement.title = this.user.label; - this.smallPodImageElement.src = this.user.iconUrl; - this.smallPodImageElement.alt = this.user.label; - this.smallPodImageElement.title = this.user.label; - this.passwordEntryContainerElement.hidden = true; - this.launchAppButtonContainerElement.hidden = false; - this.nameElement.textContent = this.user.label; - this.smallPodNameElement.textContent = this.user.label; - this.reauthNameHintElement.textContent = this.user.label; - - UserPod.prototype.updateActionBoxArea.call(this); - UserPod.prototype.customizeUserPodPerUserType.call(this); - }, - - /** @override */ - get mainInput() { - return this.launchAppButtonElement; - }, - - /** @override */ - focusInput: function() { - // Move tabIndex from the whole pod to the main input. - this.tabIndex = -1; - this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT; - this.mainInput.focus(); - }, - - /** @override */ - get forceOnlineSignin() { - return false; - }, - - /** @override */ - activate: function(e) { - var diagnosticMode = e && e.ctrlKey; - this.launchApp_(this.user, diagnosticMode); - return true; - }, - - /** @override */ - handleClickOnPod_: function(e) { - if (this.parentNode.disabled) - return; - - if (this.getPodStyle() != UserPod.Style.LARGE) { - $('pod-row').switchMainPod(this); - return; - } - - Oobe.clearErrors(); - this.parentNode.lastFocusedPod_ = this; - this.activate(e); - }, - - /** - * Launch the app. If |diagnosticMode| is true, ask user to confirm. - * @param {Object} app App data. - * @param {boolean} diagnosticMode Whether to run the app in diagnostic - * mode. - */ - launchApp_: function(app, diagnosticMode) { - if (!diagnosticMode) { - chrome.send('launchKioskApp', [app.id, false]); - return; - } - - var oobe = $('oobe'); - if (!oobe.confirmDiagnosticMode_) { - oobe.confirmDiagnosticMode_ = - new cr.ui.dialogs.ConfirmDialog(document.body); - oobe.confirmDiagnosticMode_.setOkLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeYes')); - oobe.confirmDiagnosticMode_.setCancelLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeNo')); - } - - oobe.confirmDiagnosticMode_.show( - loadTimeData.getStringF('confirmKioskAppDiagnosticModeFormat', - app.label), - function() { - chrome.send('launchKioskApp', [app.id, true]); - }); - }, - }; - - /** * Creates a new pod row element. * @constructor * @extends {HTMLDivElement} @@ -3052,12 +2925,6 @@ userPodHeight_: 0, userPodWidth_: 0, - // Array of apps that are shown in addition to other user pods. - apps_: [], - - // True to show app pods along with user pods. - shouldShowApps_: true, - // Array of users that are shown (public/supervised/regular). users_: [], @@ -3074,6 +2941,9 @@ // Whether we should add background behind user pods. showPodBackground_: false, + // Current UI state of the sign-in screen. + signinUIState_: SIGNIN_UI_STATE.HIDDEN, + /** @override */ decorate: function() { // Event listeners that are installed for the time period during which @@ -3122,20 +2992,6 @@ }, /** - * Returns pod with the given app id. - * @param {!string} app_id Application id to be matched. - * @return {Object} Pod with the given app id. null if pod hasn't been - * found. - */ - getPodWithAppId_: function(app_id) { - for (var i = 0, pod; pod = this.pods[i]; ++i) { - if (pod.user.isApp && pod.user.id == app_id) - return pod; - } - return null; - }, - - /** * Returns pod with the given username (null if there is no such pod). * @param {string} username Username to be matched. * @return {Object} Pod with the given username. null if pod hasn't been @@ -3174,8 +3030,6 @@ userPod = new DesktopUserPod({user: user}); else if (user.publicAccount) userPod = new PublicAccountUserPod({user: user}); - else if (user.isApp) - userPod = new KioskAppPod({user: user}); else userPod = new UserPod({user: user}); @@ -3212,23 +3066,6 @@ }, /** - * Runs app with a given id from the list of loaded apps. - * @param {!string} app_id of an app to run. - * @param {boolean=} opt_diagnosticMode Whether to run the app in - * diagnostic mode. Default is false. - */ - findAndRunAppForTesting: function(app_id, opt_diagnosticMode) { - var app = this.getPodWithAppId_(app_id); - if (app) { - var activationEvent = cr.doc.createEvent('MouseEvents'); - var ctrlKey = opt_diagnosticMode; - activationEvent.initMouseEvent('click', true, true, null, - 0, 0, 0, 0, 0, ctrlKey, false, false, false, 0, null); - app.dispatchEvent(activationEvent); - } - }, - - /** * Enables or disables the pin keyboard for the given user. A disabled pin * keyboard will never be displayed. * @@ -3330,7 +3167,22 @@ }, /** - * Rebuilds pod row using users_ and apps_ that were previously set or + * Current header bar UI / sign in state. + * + * @type {number} state Current state of the sign-in screen (see + * SIGNIN_UI_STATE). + */ + get signinUIState() { + return this.signinUIState_; + }, + + set signinUIState(state) { + this.signinUIState_ = state; + this.rebuildPods(); + }, + + /** + * Rebuilds pod row using users_ that were previously set or * updated. */ rebuildPods: function() { @@ -3355,12 +3207,6 @@ for (var i = 0, pod; pod = this.pods[i]; ++i) this.podsWithPendingImages_.push(pod); - // TODO(nkostylev): Edge case handling when kiosk apps are not fitting. - if (this.shouldShowApps_) { - for (var i = 0; i < this.apps_.length; ++i) - this.addUserPod(this.apps_[i]); - } - // Make sure we eventually show the pod row, even if some image is stuck. setTimeout(function() { $('pod-row').classList.remove('images-loading'); @@ -3369,8 +3215,8 @@ this.bottomMask.classList.remove('images-loading'); }.bind(this), POD_ROW_IMAGES_LOAD_TIMEOUT_MS); - var isAccountPicker = $('login-header-bar').signinUIState == - SIGNIN_UI_STATE.ACCOUNT_PICKER; + var isAccountPicker = + this.signinUIState_ == SIGNIN_UI_STATE.ACCOUNT_PICKER; // Immediately recalculate pods layout only when current UI is account // picker. Otherwise postpone it. @@ -3385,14 +3231,6 @@ }, 0); } else { this.podPlacementPostponed_ = true; - - // Update [Cancel] button state. - if ($('login-header-bar').signinUIState == - SIGNIN_UI_STATE.GAIA_SIGNIN && - emptyPodRow && - this.pods.length > 0) { - login.GaiaSigninScreen.updateControlsState(); - } } }, @@ -3421,33 +3259,6 @@ }, /** - * Adds given apps to the pod row. - * @param {array} apps Array of apps. - */ - setApps: function(apps) { - this.apps_ = apps; - this.rebuildPods(); - chrome.send('kioskAppsLoaded'); - - // Check whether there's a pending kiosk app error. - window.setTimeout(function() { - chrome.send('checkKioskAppLaunchError'); - }, 500); - }, - - /** - * Sets whether should show app pods. - * @param {boolean} shouldShowApps Whether app pods should be shown. - */ - setShouldShowApps: function(shouldShowApps) { - if (this.shouldShowApps_ == shouldShowApps) - return; - - this.shouldShowApps_ = shouldShowApps; - this.rebuildPods(); - }, - - /** * Shows a custom icon on a user pod besides the input field. * @param {string} username Username of pod to add button * @param {!{id: !string, @@ -3718,7 +3529,7 @@ */ onWindowResize: function() { var isAccountPicker = - $('login-header-bar').signinUIState == SIGNIN_UI_STATE.ACCOUNT_PICKER; + this.signinUIState_ == SIGNIN_UI_STATE.ACCOUNT_PICKER; if (isAccountPicker) { // Redo pod placement if account picker is the current screen. this.placePods_(); @@ -4425,8 +4236,6 @@ var pods = this.pods; for (var pod of pods) pod.classList.toggle('show-pod-background', showPodBackground); - $('login-header-bar') - .classList.toggle('translucent-background', showPodBackground); var isShowingScrollList = this.smallPodsContainer.classList.contains('scroll'); @@ -4524,13 +4333,11 @@ podToFocus.focus(); } - if (!podToFocus.user.isApp) { - // Only updates wallpaper when the focused pod is in large style. - chrome.send('focusPod', [ - podToFocus.user.username, - podToFocus.getPodStyle() == UserPod.Style.LARGE - ]); - } + // Only updates wallpaper when the focused pod is in large style. + chrome.send('focusPod', [ + podToFocus.user.username, + podToFocus.getPodStyle() == UserPod.Style.LARGE + ]); this.firstShown_ = false; this.lastFocusedPod_ = podToFocus; this.setUserPodFingerprintIcon( @@ -4701,8 +4508,6 @@ // Return focus back to single pod. if (this.alwaysFocusSinglePod && !pod) { - if ($('login-header-bar').contains(e.target)) - return; this.focusPod(this.focusedPod_, true /* force */); this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown'); this.focusedPod_.isActionBoxMenuHovered = false; @@ -4929,12 +4734,6 @@ this.ownerDocument.addEventListener( event, this.listeners_[event][0], this.listeners_[event][1]); } - $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR; - // Header bar should be hidden when virtual keyboard is shown, or - // views-based shelf is shown. - Oobe.getInstance().headerHidden = - this.isScreenShrinked_() || Oobe.getInstance().showingViewsBasedShelf; - if (this.podPlacementPostponed_) { this.podPlacementPostponed_ = false; this.placePods_(); @@ -4955,7 +4754,6 @@ this.ownerDocument.removeEventListener( event, this.listeners_[event][0], this.listeners_[event][1]); } - $('login-header-bar').buttonsTabIndex = 0; // Clear global states that should only applies to account picker. $('scroll-container').classList.remove('disable-scroll');
diff --git a/ui/login/account_picker/chromeos_user_pod_template.html b/ui/login/account_picker/chromeos_user_pod_template.html index 0161e8d5..1370221b 100644 --- a/ui/login/account_picker/chromeos_user_pod_template.html +++ b/ui/login/account_picker/chromeos_user_pod_template.html
@@ -95,9 +95,6 @@ <span class="reauth-warning"></span> <span class="reauth-name-hint"></span> </div> - <div class="launch-app-button-container" hidden> - <button class="launch-app-button">$i18n{launchAppButton}</button> - </div> <div class="input-line"> <svg> <line x1="0" y1="0" x2="204" y2="0">
diff --git a/ui/login/account_picker/screen_account_picker.js b/ui/login/account_picker/screen_account_picker.js index af7f756..78f31c0 100644 --- a/ui/login/account_picker/screen_account_picker.js +++ b/ui/login/account_picker/screen_account_picker.js
@@ -24,10 +24,6 @@ return { EXTERNAL_API: [ 'loadUsers', - 'runAppForTesting', - 'setApps', - 'setShouldShowApps', - 'showAppError', 'updateUserImage', 'setCapsLockState', 'removeUser', @@ -106,7 +102,6 @@ chrome.send('loginUIStateChanged', ['account-picker', true]); $('login-header-bar').signinUIState = SIGNIN_UI_STATE.ACCOUNT_PICKER; // Header bar should be always visible on Account Picker screen. - Oobe.getInstance().headerHidden = false; chrome.send('hideCaptivePortal'); var podRow = $('pod-row'); podRow.handleBeforeShow(); @@ -264,45 +259,6 @@ }, /** - * Runs app with a given id from the list of loaded apps. - * @param {!string} app_id of an app to run. - * @param {boolean=} opt_diagnostic_mode Whether to run the app in - * diagnostic mode. Default is false. - */ - runAppForTesting: function(app_id, opt_diagnostic_mode) { - $('pod-row').findAndRunAppForTesting(app_id, opt_diagnostic_mode); - }, - - /** - * Adds given apps to the pod row. - * @param {array} apps Array of apps. - */ - setApps: function(apps) { - $('pod-row').setApps(apps); - }, - - /** - * Sets the flag of whether app pods should be visible. - * @param {boolean} shouldShowApps Whether to show app pods. - */ - setShouldShowApps: function(shouldShowApps) { - $('pod-row').setShouldShowApps(shouldShowApps); - }, - - /** - * Shows the given kiosk app error message. - * @param {!string} message Error message to show. - */ - showAppError: function(message) { - // TODO(nkostylev): Figure out a way to show kiosk app launch error - // pointing to the kiosk app pod. - /** @const */ var BUBBLE_PADDING = 12; - $('bubble').showTextForElement( - $('pod-row'), message, cr.ui.Bubble.Attachment.BOTTOM, - $('pod-row').offsetWidth / 2, BUBBLE_PADDING); - }, - - /** * Updates current image of a user. * @param {string} username User for which to update the image. */
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css index 8ec451da..d8c0301 100644 --- a/ui/login/account_picker/user_pod_row.css +++ b/ui/login/account_picker/user_pod_row.css
@@ -427,20 +427,6 @@ width: 27px; } -.launch-app-button-container { - display: block; - flex: auto; - text-align: center; -} - -.launch-app-button { - display: inline; - margin-top: 6px !important; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; -} - .pod[auth-type='onlineSignIn'] .reauth-hint-container { display: flex; justify-content: center;
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 4c3ff254..971899d 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -1031,22 +1031,6 @@ }, /** - * Gets the container holding the launch app button. - * @type {!HTMLButtonElement} - */ - get launchAppButtonContainerElement() { - return this.querySelector('.launch-app-button-container'); - }, - - /** - * Gets launch app button. - * @type {!HTMLButtonElement} - */ - get launchAppButtonElement() { - return this.querySelector('.launch-app-button'); - }, - - /** * Gets action box area. * @type {!HTMLInputElement} */ @@ -1193,7 +1177,7 @@ }, updateActionBoxArea: function() { - if (this.user_.publicAccount || this.user_.isApp) { + if (this.user_.publicAccount) { this.actionBoxAreaElement.hidden = true; return; } @@ -1239,8 +1223,6 @@ } else { this.querySelector('.mp-policy-not-allowed-msg').hidden = false; } - } else if (this.user_.isApp) { - this.setUserPodIconType('app'); } }, @@ -2542,109 +2524,6 @@ }; /** - * Creates a user pod that represents kiosk app. - * @constructor - * @extends {UserPod} - */ - var KioskAppPod = cr.ui.define(function() { - var node = UserPod(); - return node; - }); - - KioskAppPod.prototype = { - __proto__: UserPod.prototype, - - /** @override */ - decorate: function() { - UserPod.prototype.decorate.call(this); - this.launchAppButtonElement.addEventListener('click', - this.activate.bind(this)); - }, - - /** @override */ - update: function() { - this.imageElement.src = this.user.iconUrl; - this.imageElement.alt = this.user.label; - this.imageElement.title = this.user.label; - this.animatedImageElement.src = this.user.iconUrl; - this.animatedImageElement.alt = this.user.label; - this.animatedImageElement.title = this.user.label; - this.passwordEntryContainerElement.hidden = true; - this.launchAppButtonContainerElement.hidden = false; - this.nameElement.textContent = this.user.label; - this.reauthNameHintElement.textContent = this.user.label; - - UserPod.prototype.updateActionBoxArea.call(this); - UserPod.prototype.customizeUserPodPerUserType.call(this); - }, - - /** @override */ - get mainInput() { - return this.launchAppButtonElement; - }, - - /** @override */ - focusInput: function() { - // Move tabIndex from the whole pod to the main input. - this.tabIndex = -1; - this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT; - this.mainInput.focus(); - }, - - /** @override */ - get forceOnlineSignin() { - return false; - }, - - /** @override */ - activate: function(e) { - var diagnosticMode = e && e.ctrlKey; - this.launchApp_(this.user, diagnosticMode); - return true; - }, - - /** @override */ - handleClickOnPod_: function(e) { - if (this.parentNode.disabled) - return; - - Oobe.clearErrors(); - this.parentNode.lastFocusedPod_ = this; - this.activate(e); - }, - - /** - * Launch the app. If |diagnosticMode| is true, ask user to confirm. - * @param {Object} app App data. - * @param {boolean} diagnosticMode Whether to run the app in diagnostic - * mode. - */ - launchApp_: function(app, diagnosticMode) { - if (!diagnosticMode) { - chrome.send('launchKioskApp', [app.id, false]); - return; - } - - var oobe = $('oobe'); - if (!oobe.confirmDiagnosticMode_) { - oobe.confirmDiagnosticMode_ = - new cr.ui.dialogs.ConfirmDialog(document.body); - oobe.confirmDiagnosticMode_.setOkLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeYes')); - oobe.confirmDiagnosticMode_.setCancelLabel( - loadTimeData.getString('confirmKioskAppDiagnosticModeNo')); - } - - oobe.confirmDiagnosticMode_.show( - loadTimeData.getStringF('confirmKioskAppDiagnosticModeFormat', - app.label), - function() { - chrome.send('launchKioskApp', [app.id, true]); - }); - }, - }; - - /** * Creates a new pod row element. * @constructor * @extends {HTMLDivElement} @@ -2679,12 +2558,6 @@ userPodHeight_: 0, userPodWidth_: 0, - // Array of apps that are shown in addition to other user pods. - apps_: [], - - // True to show app pods along with user pods. - shouldShowApps_: true, - // Array of users that are shown (public/supervised/regular). users_: [], @@ -2738,20 +2611,6 @@ }, /** - * Returns pod with the given app id. - * @param {!string} app_id Application id to be matched. - * @return {Object} Pod with the given app id. null if pod hasn't been - * found. - */ - getPodWithAppId_: function(app_id) { - for (var i = 0, pod; pod = this.pods[i]; ++i) { - if (pod.user.isApp && pod.user.id == app_id) - return pod; - } - return null; - }, - - /** * Returns pod with the given username (null if there is no such pod). * @param {string} username Username to be matched. * @return {Object} Pod with the given username. null if pod hasn't been @@ -2790,8 +2649,6 @@ userPod = new DesktopUserPod({user: user}); else if (user.publicAccount) userPod = new PublicAccountUserPod({user: user}); - else if (user.isApp) - userPod = new KioskAppPod({user: user}); else userPod = new UserPod({user: user}); @@ -2828,23 +2685,6 @@ }, /** - * Runs app with a given id from the list of loaded apps. - * @param {!string} app_id of an app to run. - * @param {boolean=} opt_diagnosticMode Whether to run the app in - * diagnostic mode. Default is false. - */ - findAndRunAppForTesting: function(app_id, opt_diagnosticMode) { - var app = this.getPodWithAppId_(app_id); - if (app) { - var activationEvent = cr.doc.createEvent('MouseEvents'); - var ctrlKey = opt_diagnosticMode; - activationEvent.initMouseEvent('click', true, true, null, - 0, 0, 0, 0, 0, ctrlKey, false, false, false, 0, null); - app.dispatchEvent(activationEvent); - } - }, - - /** * Enables or disables the pin keyboard for the given user. A disabled pin * keyboard will never be displayed. * @@ -2967,8 +2807,7 @@ }, /** - * Rebuilds pod row using users_ and apps_ that were previously set or - * updated. + * Rebuilds pod row using users_ that were previously set or updated. */ rebuildPods: function() { var emptyPodRow = this.pods.length == 0; @@ -2989,12 +2828,6 @@ for (var i = 0, pod; pod = this.pods[i]; ++i) this.podsWithPendingImages_.push(pod); - // TODO(nkostylev): Edge case handling when kiosk apps are not fitting. - if (this.shouldShowApps_) { - for (var i = 0; i < this.apps_.length; ++i) - this.addUserPod(this.apps_[i]); - } - // Make sure we eventually show the pod row, even if some image is stuck. setTimeout(function() { $('pod-row').classList.remove('images-loading'); @@ -3016,45 +2849,10 @@ }, 0); } else { this.podPlacementPostponed_ = true; - - // Update [Cancel] button state. - if ($('login-header-bar').signinUIState == - SIGNIN_UI_STATE.GAIA_SIGNIN && - emptyPodRow && - this.pods.length > 0) { - login.GaiaSigninScreen.updateControlsState(); - } } }, /** - * Adds given apps to the pod row. - * @param {array} apps Array of apps. - */ - setApps: function(apps) { - this.apps_ = apps; - this.rebuildPods(); - chrome.send('kioskAppsLoaded'); - - // Check whether there's a pending kiosk app error. - window.setTimeout(function() { - chrome.send('checkKioskAppLaunchError'); - }, 500); - }, - - /** - * Sets whether should show app pods. - * @param {boolean} shouldShowApps Whether app pods should be shown. - */ - setShouldShowApps: function(shouldShowApps) { - if (this.shouldShowApps_ == shouldShowApps) - return; - - this.shouldShowApps_ = shouldShowApps; - this.rebuildPods(); - }, - - /** * Shows a custom icon on a user pod besides the input field. * @param {string} username Username of pod to add button * @param {!{id: !string, @@ -3539,10 +3337,8 @@ podToFocus.focus(); } - if (!podToFocus.user.isApp) - chrome.send( - 'focusPod', - [podToFocus.user.username, true /* loads wallpaper */]); + chrome.send( + 'focusPod', [podToFocus.user.username, true /* loads wallpaper */]); this.firstShown_ = false; this.lastFocusedPod_ = podToFocus; this.scrollFocusedPodIntoView();
diff --git a/ui/login/account_picker/user_pod_template.html b/ui/login/account_picker/user_pod_template.html index 367374f..5235cfa 100644 --- a/ui/login/account_picker/user_pod_template.html +++ b/ui/login/account_picker/user_pod_template.html
@@ -81,9 +81,6 @@ <span class="reauth-warning"></span> <span class="reauth-name-hint"></span> </div> - <div class="launch-app-button-container" hidden> - <button class="launch-app-button">$i18n{launchAppButton}</button> - </div> </div> </div> <div class="action-box-area">
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js index c86684e..f8e3f00 100644 --- a/ui/login/display_manager.js +++ b/ui/login/display_manager.js
@@ -285,10 +285,6 @@ document.documentElement.setAttribute('screen', displayType); }, - get newKioskUI() { - return loadTimeData.getString('newKioskUI') == 'on'; - }, - /** * Returns dimensions of screen exluding header bar. * @type {Object} @@ -307,32 +303,6 @@ }, /** - * Hides/shows header (Shutdown/Add User/Cancel buttons). - * @param {boolean} hidden Whether header is hidden. - * TODO(crbug/914578): talk to the views login shelf through Mojo. - */ - get headerHidden() { - return $('login-header-bar').hidden; - }, - - set headerHidden(hidden) { - if (this.showingViewsBasedShelf && !hidden) { - // When views-based shelf is enabled, toggling header bar visibility - // is handled by ash. Prevent showing a duplicate header bar here. - return; - } - $('login-header-bar').hidden = hidden; - }, - - /** - * The header bar should be hidden when views-based shelf is shown. - */ - get showingViewsBasedShelf() { - // TODO: remove this method once webui shelf has been removed. - return true; - }, - - /** * Returns true if we are showing views based login screen. * @return {boolean} */ @@ -727,16 +697,10 @@ // Make sure the screen is decorated. this.preloadScreen(screen); - if (screen.data !== undefined && screen.data.disableAddUser) - DisplayManager.updateAddUserButtonStatus(true); - // Show sign-in screen instead of account picker if pod row is empty. if (screenId == SCREEN_ACCOUNT_PICKER && $('pod-row').pods.length == 0 && cr.isChromeOS) { - // Manually hide 'add-user' header bar, because of the case when - // 'Cancel' button is used on the offline login page. - $('add-user-header-bar-item').hidden = true; Oobe.showSigninUI(); return; } @@ -1309,22 +1273,9 @@ }; /** - * Disable Add users button if said. - * @param {boolean} disable true to disable + * Clears password field in user-pod. */ - DisplayManager.updateAddUserButtonStatus = - function(disable) { - $('add-user-button').disabled = disable; - $('add-user-button') - .classList[disable ? 'add' : 'remove']('button-restricted'); - $('add-user-button').title = - disable ? loadTimeData.getString('disabledAddUserTooltip') : ''; - } - - /** - * Clears password field in user-pod. - */ - DisplayManager.clearUserPodPassword = function() { + DisplayManager.clearUserPodPassword = function() { $('pod-row').clearFocusedPod(); };
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index 08d5bc5..0df107b 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -587,6 +587,11 @@ } bool NativeThemeWin::SystemDarkModeEnabled() const { + // Windows high contrast modes are entirely different themes, + // so let them take priority over dark mode. + // ...unless --force-dark-mode was specified in which case caveat emptor. + if (UsesHighContrastColors() && !NativeTheme::SystemDarkModeEnabled()) + return false; bool fDarkModeEnabled = false; if (hkcu_themes_regkey_.Valid()) { DWORD apps_use_light_theme = 1;
diff --git a/ui/ozone/platform/wayland/test/mock_surface.h b/ui/ozone/platform/wayland/test/mock_surface.h index 1140ce2..0f83878b 100644 --- a/ui/ozone/platform/wayland/test/mock_surface.h +++ b/ui/ozone/platform/wayland/test/mock_surface.h
@@ -5,10 +5,14 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_SURFACE_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_SURFACE_H_ +#include <memory> +#include <utility> + #include <wayland-server-protocol-core.h> #include "base/macros.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -38,8 +42,14 @@ } MockXdgSurface* xdg_surface() const { return xdg_surface_.get(); } + void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { + xdg_popup_ = std::move(xdg_popup); + } + MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } + private: std::unique_ptr<MockXdgSurface> xdg_surface_; + std::unique_ptr<MockXdgPopup> xdg_popup_; DISALLOW_COPY_AND_ASSIGN(MockSurface); };
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc index cecb5a9..6970b63 100644 --- a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc +++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc
@@ -26,7 +26,10 @@ &Grab, // grab }; -MockXdgPopup::MockXdgPopup(wl_resource* resource) : ServerObject(resource) {} +MockXdgPopup::MockXdgPopup(wl_resource* resource, const void* implementation) + : ServerObject(resource) { + SetImplementationUnretained(resource, implementation, this); +} MockXdgPopup::~MockXdgPopup() {}
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.h b/ui/ozone/platform/wayland/test/mock_xdg_popup.h index 4ece023c..4ebb050 100644 --- a/ui/ozone/platform/wayland/test/mock_xdg_popup.h +++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.h
@@ -5,12 +5,15 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_POPUP_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_POPUP_H_ +#include <utility> + #include <xdg-shell-unstable-v5-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> #include "base/macros.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/ozone/platform/wayland/test/server_object.h" +#include "ui/ozone/platform/wayland/test/test_positioner.h" struct wl_resource; @@ -21,12 +24,27 @@ class MockXdgPopup : public ServerObject { public: - MockXdgPopup(wl_resource* resource); + MockXdgPopup(wl_resource* resource, const void* implementation); ~MockXdgPopup() override; MOCK_METHOD1(Grab, void(uint32_t serial)); + void set_position(struct TestPositioner::PopupPosition position) { + position_ = std::move(position); + } + + gfx::Rect anchor_rect() const { return position_.anchor_rect; } + gfx::Size size() const { return position_.size; } + uint32_t anchor() const { return position_.anchor; } + uint32_t gravity() const { return position_.gravity; } + uint32_t constraint_adjustment() const { + return position_.constraint_adjustment; + } + private: + // Position of the popup. Used only with V6. + struct TestPositioner::PopupPosition position_; + DISALLOW_COPY_AND_ASSIGN(MockXdgPopup); };
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc index a3cb6653..0941ace 100644 --- a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc +++ b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc
@@ -72,9 +72,13 @@ return; } - CreateResourceWithImpl<MockXdgPopup>(client, &xdg_popup_interface, - wl_resource_get_version(resource), - &kXdgPopupImpl, id); + wl_resource* xdg_popup_resource = wl_resource_create( + client, &xdg_popup_interface, wl_resource_get_version(resource), id); + + auto mock_xdg_popup = + std::make_unique<MockXdgPopup>(xdg_popup_resource, &kXdgPopupImpl); + + mock_surface->set_xdg_popup(std::move(mock_xdg_popup)); } void Pong(wl_client* client, wl_resource* resource, uint32_t serial) {
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc index 8797a94c..06f1d58 100644 --- a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc +++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc
@@ -104,17 +104,22 @@ return; } + wl_resource* xdg_popup_resource = wl_resource_create( + client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), id); auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource); - if (positioner->size().width() == 0 || - positioner->anchor_rect().width() == 0) { + DCHECK(positioner); + + auto mock_xdg_popup = + std::make_unique<MockXdgPopup>(xdg_popup_resource, &kZxdgPopupV6Impl); + mock_xdg_popup->set_position(positioner->position()); + if (mock_xdg_popup->size().IsEmpty() || + mock_xdg_popup->anchor_rect().IsEmpty()) { wl_resource_post_error(resource, ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER, "Positioner object is not complete"); return; } - CreateResourceWithImpl<MockXdgPopup>(client, &zxdg_popup_v6_interface, - wl_resource_get_version(resource), - &kZxdgPopupV6Impl, id); + mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup)); } const struct xdg_surface_interface kMockXdgSurfaceImpl = {
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.h b/ui/ozone/platform/wayland/test/mock_xdg_surface.h index 3793f25b..0576a1e 100644 --- a/ui/ozone/platform/wayland/test/mock_xdg_surface.h +++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.h
@@ -5,10 +5,14 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_SURFACE_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_SURFACE_H_ +#include <memory> +#include <utility> + #include <xdg-shell-unstable-v5-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> #include "testing/gmock/include/gmock/gmock.h" +#include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" #include "ui/ozone/platform/wayland/test/server_object.h" struct wl_resource; @@ -49,10 +53,17 @@ } MockXdgTopLevel* xdg_toplevel() const { return xdg_toplevel_.get(); } + void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { + xdg_popup_ = std::move(xdg_popup); + } + MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } + private: // Used when xdg v6 is used. std::unique_ptr<MockXdgTopLevel> xdg_toplevel_; + std::unique_ptr<MockXdgPopup> xdg_popup_; + DISALLOW_COPY_AND_ASSIGN(MockXdgSurface); };
diff --git a/ui/ozone/platform/wayland/test/test_positioner.cc b/ui/ozone/platform/wayland/test/test_positioner.cc index e576711..6fbf7232 100644 --- a/ui/ozone/platform/wayland/test/test_positioner.cc +++ b/ui/ozone/platform/wayland/test/test_positioner.cc
@@ -69,16 +69,23 @@ GetUserDataAs<TestPositioner>(resource)->set_gravity(gravity); } +void SetConstraintAdjustment(struct wl_client* client, + struct wl_resource* resource, + uint32_t constraint_adjustment) { + GetUserDataAs<TestPositioner>(resource)->set_constraint_adjustment( + constraint_adjustment); +} + } // namespace const struct zxdg_positioner_v6_interface kTestZxdgPositionerV6Impl = { - &DestroyResource, // destroy - &SetSize, // set_size - &SetAnchorRect, // set_anchor_rect - &SetAnchor, // set_anchor - &SetGravity, // set_gravity - nullptr, // set_constraint_adjustment - nullptr, // set_offset + &DestroyResource, // destroy + &SetSize, // set_size + &SetAnchorRect, // set_anchor_rect + &SetAnchor, // set_anchor + &SetGravity, // set_gravity + &SetConstraintAdjustment, // set_constraint_adjustment + nullptr, // set_offset }; TestPositioner::TestPositioner(wl_resource* resource)
diff --git a/ui/ozone/platform/wayland/test/test_positioner.h b/ui/ozone/platform/wayland/test/test_positioner.h index 58a3ff4..872f57c 100644 --- a/ui/ozone/platform/wayland/test/test_positioner.h +++ b/ui/ozone/platform/wayland/test/test_positioner.h
@@ -5,6 +5,8 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_POSITIONER_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_POSITIONER_H_ +#include <utility> + #include <xdg-shell-unstable-v6-server-protocol.h> #include "base/macros.h" @@ -22,24 +24,30 @@ // surface relative to a parent surface. class TestPositioner : public ServerObject { public: + struct PopupPosition { + gfx::Rect anchor_rect; + gfx::Size size; + uint32_t anchor = 0; + uint32_t gravity = 0; + uint32_t constraint_adjustment = 0; + }; + explicit TestPositioner(wl_resource* resource); ~TestPositioner() override; - void set_size(gfx::Size size) { size_ = size; } - gfx::Size size() const { return size_; } - - void set_anchor_rect(gfx::Rect anchor_rect) { anchor_rect_ = anchor_rect; } - gfx::Rect anchor_rect() const { return anchor_rect_; } - - void set_anchor(uint32_t anchor) { anchor_ = anchor; } - - void set_gravity(uint32_t gravity) { gravity_ = gravity; } + PopupPosition position() { return std::move(position_); } + void set_size(gfx::Size size) { position_.size = size; } + void set_anchor_rect(gfx::Rect anchor_rect) { + position_.anchor_rect = anchor_rect; + } + void set_anchor(uint32_t anchor) { position_.anchor = anchor; } + void set_gravity(uint32_t gravity) { position_.gravity = gravity; } + void set_constraint_adjustment(uint32_t constraint_adjustment) { + position_.constraint_adjustment = constraint_adjustment; + } private: - gfx::Rect anchor_rect_; - gfx::Size size_; - uint32_t anchor_; - uint32_t gravity_; + PopupPosition position_; DISALLOW_COPY_AND_ASSIGN(TestPositioner); };
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.cc b/ui/ozone/platform/wayland/wayland_keyboard.cc index 82677ae..910a5ec 100644 --- a/ui/ozone/platform/wayland/wayland_keyboard.cc +++ b/ui/ozone/platform/wayland/wayland_keyboard.cc
@@ -13,10 +13,10 @@ #include "ui/events/event.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" #include "ui/events/ozone/evdev/keyboard_util_evdev.h" #include "ui/events/ozone/layout/keyboard_layout_engine.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" -#include "ui/events/ozone/layout/layout_util.h" #include "ui/ozone/platform/wayland/wayland_connection.h" #include "ui/ozone/platform/wayland/wayland_window.h"
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc index 0ffa1228..0245365 100644 --- a/ui/ozone/platform/wayland/wayland_window.cc +++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -66,11 +66,20 @@ DISALLOW_COPY_AND_ASSIGN(XDGShellObjectFactory); }; +// Translates bounds relative to top level window to specified parent. gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, const gfx::Rect& parent_bounds) { - int x = child_bounds.x() - parent_bounds.x(); - int y = child_bounds.y() - parent_bounds.y(); - return gfx::Rect(gfx::Point(x, y), child_bounds.size()); + return gfx::Rect(gfx::Point(child_bounds.x() - parent_bounds.x(), + child_bounds.y() - parent_bounds.y()), + child_bounds.size()); +} + +// Translates bounds relative to parent window to top level window. +gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds) { + return gfx::Rect(gfx::Point(child_bounds.x() + parent_bounds.x(), + child_bounds.y() + parent_bounds.y()), + child_bounds.size()); } } // namespace @@ -183,8 +192,7 @@ DCHECK(parent_window_ && !xdg_popup_); - gfx::Rect bounds = - TranslateBoundsToParentCoordinates(bounds_, parent_window_->GetBounds()); + auto bounds = AdjustPopupWindowPosition(); xdg_popup_ = xdg_shell_objects_factory_->CreateXDGPopup(connection_, this); if (!xdg_popup_ || @@ -235,9 +243,9 @@ void WaylandWindow::ApplyPendingBounds() { if (pending_bounds_.IsEmpty()) return; + DCHECK(xdg_surface_); SetBounds(pending_bounds_); - DCHECK(xdg_surface_); xdg_surface_->SetWindowGeometry(bounds_); xdg_surface_->AckConfigure(); pending_bounds_ = gfx::Rect(); @@ -514,6 +522,8 @@ bool is_maximized, bool is_fullscreen, bool is_activated) { + DCHECK(!xdg_popup()); + // Propagate the window state information to the client. PlatformWindowState old_state = state_; @@ -591,6 +601,48 @@ MaybeTriggerPendingStateChange(); } +void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds) { + DCHECK(xdg_popup()); + gfx::Rect new_bounds = bounds; + + // It's not enough to just set new bounds. If it is a menu window, whose + // parent is a top level window aka browser window, it can be flipped + // vertically along y-axis and have negative values set. Chromium cannot + // understand that and starts to position nested menu windows incorrectly. To + // fix that, we have to bear in mind that Wayland compositor does not share + // global coordinates for any surfaces, and Chromium assumes the top level + // window is always located at 0,0 origin. What is more, child windows must + // always be positioned relative to parent window local surface coordinates. + // Thus, if the menu window is flipped along y-axis by Wayland and its origin + // is above the top level parent window, the origin of the top level window + // has to be shifted by that value on y-axis so that the origin of the menu + // becomes x,0, and events can be handled normally. + if (!parent_window_->xdg_popup()) { + gfx::Rect parent_bounds = parent_window_->GetBounds(); + // The menu window is flipped along y-axis and have x,-y origin. Shift the + // parent top level window instead. + if (new_bounds.y() < 0) { + // Move parent bounds along y-axis. + parent_bounds.set_y(-(new_bounds.y())); + new_bounds.set_y(0); + } else { + // If the menu window is located at correct origin from the browser point + // of view, return the top level window back to 0,0. + parent_bounds.set_y(0); + } + parent_window_->SetBounds(parent_bounds); + } else { + // The nested menu windows are located relative to the parent menu windows. + // Thus, the location must be translated to be relative to the top level + // window, which automatically becomes the same as relative to an origin of + // a display. + new_bounds = TranslateBoundsToTopLevelCoordinates( + new_bounds, parent_window_->GetBounds()); + DCHECK(new_bounds.y() >= 0); + } + SetBounds(new_bounds); +} + void WaylandWindow::OnCloseRequest() { // Before calling OnCloseRequest, the |xdg_popup_| must become hidden and // only then call OnCloseRequest(). @@ -753,6 +805,50 @@ } } +gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const { + auto* parent_window = parent_window_->xdg_popup() + ? parent_window_->parent_window_ + : parent_window_; + DCHECK(parent_window); + // Chromium positions windows in screen coordinates, but Wayland requires them + // to be in local surface coordinates aka relative to parent window. + const gfx::Rect parent_bounds = parent_window_->GetBounds(); + gfx::Rect new_bounds = + TranslateBoundsToParentCoordinates(bounds_, parent_bounds); + + // Chromium may decide to position nested menu windows on the left side + // instead of the right side of parent menu windows when the size of the + // window becomes larger than the display it is shown on. It's correct when + // the window is located on one display and occupies the whole work area, but + // as soon as it's moved and there is space on the right side, Chromium + // continues positioning the nested menus on the left side relative to the + // parent menu (Wayland does not provide clients with global coordinates). + // Instead, reposition that window to be on the right side of the parent menu + // window and let the compositor decide how to position it if it does not fit + // a single display. However, there is one exception - if the window is + // maximized, let Chromium position it on the left side as long as the Wayland + // compositor may decide to position the nested window on the right side of + // the parent menu window, which results in showing it on a second display if + // more than one display is used. + if (parent_window_->xdg_popup() && parent_window_->parent_window_ && + !parent_window_->parent_window_->IsMaximized()) { + auto* top_level_window = parent_window_->parent_window_; + DCHECK(top_level_window && !top_level_window->xdg_popup()); + if (new_bounds.x() <= 0 && !top_level_window->IsMaximized()) { + // Position the child menu window on the right side of the parent window + // and let the Wayland compositor decide how to do constraint + // adjustements. + int new_x = parent_bounds.width() - (new_bounds.width() + new_bounds.x()); + new_bounds.set_x(new_x); + } + } + return new_bounds; +} + +WaylandWindow* WaylandWindow::GetTopLevelWindow() { + return parent_window_ ? parent_window_->GetTopLevelWindow() : this; +} + // static void WaylandWindow::Enter(void* data, struct wl_surface* wl_surface,
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h index 5a97c35..7a32d8dc 100644 --- a/ui/ozone/platform/wayland/wayland_window.h +++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -134,6 +134,7 @@ bool is_maximized, bool is_fullscreen, bool is_activated); + void HandlePopupConfigure(const gfx::Rect& bounds); void OnCloseRequest(); @@ -173,6 +174,11 @@ void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event); + // Returns bounds with origin relative to parent window's origin. + gfx::Rect AdjustPopupWindowPosition() const; + + WaylandWindow* GetTopLevelWindow(); + // wl_surface_listener static void Enter(void* data, struct wl_surface* wl_surface,
diff --git a/ui/ozone/platform/wayland/wayland_window_unittest.cc b/ui/ozone/platform/wayland/wayland_window_unittest.cc index d3a99e1..c85ff8e 100644 --- a/ui/ozone/platform/wayland/wayland_window_unittest.cc +++ b/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -4,6 +4,8 @@ #include "ui/ozone/platform/wayland/wayland_window.h" +#include <memory> + #include <linux/input.h> #include <wayland-server-core.h> #include <xdg-shell-unstable-v5-server-protocol.h> @@ -34,6 +36,14 @@ namespace { +struct PopupPosition { + gfx::Rect anchor_rect; + gfx::Size size; + uint32_t anchor = 0; + uint32_t gravity = 0; + uint32_t constraint_adjustment = 0; +}; + class ScopedWlArray { public: ScopedWlArray() { wl_array_init(&array_); } @@ -100,6 +110,18 @@ width, height, states); } + void SendConfigureEventPopup(gfx::AcceleratedWidget menu_widget, + const gfx::Rect bounds) { + auto* popup = GetPopupByWidget(menu_widget); + ASSERT_TRUE(popup); + if (GetParam() == kXdgShellV5) { + LOG(WARNING) << "XDG V5 does not support configure events for popups."; + } else { + zxdg_popup_v6_send_configure(popup->resource(), bounds.x(), bounds.y(), + bounds.width(), bounds.height()); + } + } + // Depending on a shell version, xdg_surface_ or xdg_toplevel surface should // get the mock calls. This method decided, which surface to use. wl::MockXdgSurface* GetXdgSurface() { @@ -159,6 +181,37 @@ Mock::VerifyAndClearExpectations(&delegate_); } + void VerifyXdgPopupPosition(gfx::AcceleratedWidget menu_widget, + const PopupPosition& position) { + auto* popup = GetPopupByWidget(menu_widget); + ASSERT_TRUE(popup); + + if (GetParam() == kXdgShellV5) { + LOG(WARNING) << "XDG V5 does not support xdg_positioner"; + return; + } + + EXPECT_EQ(popup->anchor_rect(), position.anchor_rect); + EXPECT_EQ(popup->size(), position.size); + EXPECT_EQ(popup->anchor(), position.anchor); + EXPECT_EQ(popup->gravity(), position.gravity); + EXPECT_EQ(popup->constraint_adjustment(), position.constraint_adjustment); + } + + wl::MockXdgPopup* GetPopupByWidget(gfx::AcceleratedWidget widget) { + wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(widget); + if (mock_surface) { + if (GetParam() == kXdgShellV5) { + return mock_surface->xdg_popup(); + } else { + auto* mock_xdg_surface = mock_surface->xdg_surface(); + if (mock_xdg_surface) + return mock_xdg_surface->xdg_popup(); + } + } + return nullptr; + } + wl::MockXdgSurface* xdg_surface_; MouseEvent test_mouse_event_; @@ -797,6 +850,253 @@ } } +// Tests WaylandWindow repositions menu windows to be relative to parent window +// in a right way. Also, tests it sends right anchor and is able to calculate +// bounds back from relative to parent to be relative to screen/toplevel window. +// All bounds values are taken by manually running the browser. +TEST_P(WaylandWindowTest, AdjustPopupBounds) { + // Only shell v6 exercises this test as long as shell v5 does not support + // positioners. + if (GetParam() == kXdgShellV5) + return; + + PopupPosition menu_window_positioner = { + gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409), + ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT, + ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT, + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y}; + + PopupPosition nested_menu_window_positioner = { + gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99), + ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT, + ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT, + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y}; + + auto* toplevel_window = window_.get(); + toplevel_window->SetBounds(gfx::Rect(0, 0, 739, 574)); + + // Case 1: the top menu window is positioned normally. + MockPlatformWindowDelegate menu_window_delegate; + gfx::Rect menu_window_bounds(gfx::Point(440, 76), + menu_window_positioner.size); + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, toplevel_window->GetWidget(), + menu_window_bounds, &menu_window_delegate); + + Sync(); + + gfx::AcceleratedWidget menu_window_widget = menu_window->GetWidget(); + VerifyXdgPopupPosition(menu_window_widget, menu_window_positioner); + + EXPECT_CALL(menu_window_delegate, OnBoundsChanged(_)).Times(0); + SendConfigureEventPopup(menu_window_widget, menu_window_bounds); + + Sync(); + + EXPECT_EQ(menu_window->GetBounds(), menu_window_bounds); + + // Case 2: the nested menu window is positioned normally. + MockPlatformWindowDelegate nested_menu_window_delegate; + gfx::Rect nested_menu_window_bounds(gfx::Point(723, 156), + nested_menu_window_positioner.size); + std::unique_ptr<WaylandWindow> nested_menu_window = + CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, + nested_menu_window_bounds, &nested_menu_window_delegate); + + Sync(); + + gfx::AcceleratedWidget nested_menu_window_widget = + nested_menu_window->GetWidget(); + VerifyXdgPopupPosition(nested_menu_window_widget, + nested_menu_window_positioner); + + EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0); + const gfx::Point origin(nested_menu_window_positioner.anchor_rect.x() + + nested_menu_window_positioner.anchor_rect.width(), + nested_menu_window_positioner.anchor_rect.y()); + gfx::Rect calculated_nested_bounds = nested_menu_window_bounds; + calculated_nested_bounds.set_origin(origin); + SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds); + + Sync(); + + EXPECT_EQ(nested_menu_window->GetBounds(), nested_menu_window_bounds); + + // Case 3: imagine the menu window was positioned near to the right edge of a + // display. Nothing changes in the way how WaylandWindow calculates bounds, + // because the Wayland compositor does not provide global location of windows. + // Though, the compositor can reposition the window (flip along x or y axis or + // slide along those axis). WaylandWindow just needs to correctly translate + // bounds from relative to parent to be relative to screen. The Wayland + // compositor does not reposition the menu, because it fits the screen, but + // the nested menu window is repositioned to the left. + EXPECT_CALL( + nested_menu_window_delegate, + OnBoundsChanged(gfx::Rect({139, 156}, nested_menu_window_bounds.size()))); + calculated_nested_bounds.set_origin({-301, 80}); + SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds); + + Sync(); + + // Case 4: imagine the top level window was moved down to the bottom edge of a + // display and only tab strip with 3-dot menu buttons left visible. In this + // case, Chromium also does not know about that and positions the window + // normally (normal bounds are sent), but the Wayland compositor flips the top + // menu window along y-axis and fixes bounds of a top level window so that it + // is located (from the Chromium point of view) below origin of the menu + // window. + EXPECT_CALL(delegate_, OnBoundsChanged( + gfx::Rect({0, 363}, window_->GetBounds().size()))); + EXPECT_CALL(menu_window_delegate, + OnBoundsChanged(gfx::Rect({440, 0}, menu_window_bounds.size()))); + SendConfigureEventPopup(menu_window_widget, + gfx::Rect({440, -363}, menu_window_bounds.size())); + + Sync(); + + // The nested menu window is also repositioned accordingly, but it's not + // Wayland compositor reposition, but rather reposition from the Chromium + // side. Thus, we have to check that anchor rect is correct. + nested_menu_window.reset(); + nested_menu_window_bounds.set_origin({723, 258}); + nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, + &nested_menu_window_delegate); + + Sync(); + + nested_menu_window_widget = nested_menu_window->GetWidget(); + // We must get the anchor on gfx::Point(4, 258). + nested_menu_window_positioner.anchor_rect.set_origin({4, 258}); + VerifyXdgPopupPosition(nested_menu_window_widget, + nested_menu_window_positioner); + + Sync(); + + EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0); + calculated_nested_bounds.set_origin({283, 258}); + SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds); + + Sync(); + + // Case 5: this case involves case 4. Thus, it concerns only the nested menu + // window. imagine that the top menu window is flipped along y-axis and + // positioned near to the right side of a display. The nested menu window is + // flipped along x-axis by the compositor and WaylandWindow must calculate + // bounds back to be relative to display correctly. If the window is near to + // the left edge of a display, nothing is going to change, and the origin will + // be the same as in the previous case. + EXPECT_CALL( + nested_menu_window_delegate, + OnBoundsChanged(gfx::Rect({149, 258}, nested_menu_window_bounds.size()))); + calculated_nested_bounds.set_origin({-291, 258}); + SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds); + + Sync(); + + // Case 6: imagine the top level window was moved back to normal position. In + // this case, the Wayland compositor positions the menu window normally and + // the WaylandWindow repositions the top level window back to 0,0 (which had + // an offset to compensate the position of the menu window fliped along + // y-axis. It just has had negative y value, which is wrong for Chromium. + EXPECT_CALL(delegate_, + OnBoundsChanged(gfx::Rect({0, 0}, window_->GetBounds().size()))); + EXPECT_CALL(menu_window_delegate, + OnBoundsChanged(gfx::Rect({440, 76}, menu_window_bounds.size()))); + SendConfigureEventPopup(menu_window_widget, + gfx::Rect({440, 76}, menu_window_bounds.size())); + + Sync(); + + VerifyAndClearExpectations(); + + // Case 7: imagine the top level window has the size corresponding near to the + // maximum work area of a display. Despite being unaware where the top level + // window is, Chromium positions the nested menu window to be on the left side + // of the menu window. But, WaylandWindow must reposition it to be on the + // right side of the menu window, and let the Wayland compositor decide how to + // position the nested menu (if its pixels do not fit one display, it can be + // flipped along x-axis). PS: all the values are taken after manually using + // the browser and logging bounds. + nested_menu_window.reset(); + menu_window.reset(); + + window_->SetBounds(gfx::Rect(0, 0, 2493, 1413)); + + menu_window_bounds.set_origin({2206, 67}); + menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, toplevel_window->GetWidget(), + menu_window_bounds, &menu_window_delegate); + + Sync(); + + menu_window_widget = menu_window->GetWidget(); + menu_window_positioner.anchor_rect.set_origin({2205, 37}); + VerifyXdgPopupPosition(menu_window_widget, menu_window_positioner); + + EXPECT_CALL(menu_window_delegate, OnBoundsChanged(_)).Times(0); + SendConfigureEventPopup(menu_window_widget, menu_window_bounds); + + Sync(); + + nested_menu_window_bounds.set_origin({1905, 147}); + nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, + &nested_menu_window_delegate); + + Sync(); + + nested_menu_window_widget = nested_menu_window->GetWidget(); + nested_menu_window_positioner.anchor_rect.set_origin({4, 80}); + VerifyXdgPopupPosition(nested_menu_window_widget, + nested_menu_window_positioner); + + VerifyAndClearExpectations(); + + // Case 8: now, the top level window becomes maximized. Compared to the case + // 7, despite having the size corresponding to the work area of a display, the + // WaylandWindow must not reposition the nested menu window to the right side, + // and let it be on the left side of a menu window as long as letting the + // Wayland compositor repositioning the nested window may result in a window + // shown on another display. + auto active_maximized = MakeStateArray( + {XDG_SURFACE_STATE_ACTIVATED, XDG_SURFACE_STATE_MAXIMIZED}); + EXPECT_CALL(*GetXdgSurface(), SetMaximized()); + + window_->Maximize(); + SendConfigureEvent(2493, 1413, 1, active_maximized.get()); + + Sync(); + + nested_menu_window.reset(); + + nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, + &nested_menu_window_delegate); + + Sync(); + + nested_menu_window_widget = nested_menu_window->GetWidget(); + // The anchor and gravity must change to be on the right side. + nested_menu_window_positioner.anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_RIGHT; + nested_menu_window_positioner.anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; + nested_menu_window_positioner.gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_RIGHT; + nested_menu_window_positioner.gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; + VerifyXdgPopupPosition(nested_menu_window_widget, + nested_menu_window_positioner); + + calculated_nested_bounds.set_origin({-301, 80}); + EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0); + SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds); + + Sync(); + + VerifyAndClearExpectations(); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test, WaylandWindowTest, ::testing::Values(kXdgShellV5));
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc b/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc index 0da36f5..80cd1ac 100644 --- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc +++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc
@@ -37,6 +37,10 @@ xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this); + // xdg_popup_v5 does not support configure events. Thus, manually call it to + // propagate final bounds. + wayland_window_->HandlePopupConfigure(bounds); + return true; }
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc index 714c8433..38b274f 100644 --- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc +++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
@@ -6,13 +6,170 @@ #include <xdg-shell-unstable-v6-client-protocol.h> +#include "ui/events/event_constants.h" #include "ui/gfx/geometry/rect.h" #include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_pointer.h" #include "ui/ozone/platform/wayland/wayland_window.h" #include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h" namespace ui { +namespace { + +constexpr uint32_t kAnchorDefaultWidth = 1; +constexpr uint32_t kAnchorDefaultHeight = 1; +constexpr uint32_t kAnchorHeightParentMenu = 30; + +enum class MenuType { + TYPE_RIGHT_CLICK, + TYPE_3DOT_PARENT_MENU, + TYPE_3DOT_CHILD_MENU, + TYPE_UNKNOWN, +}; + +uint32_t GetAnchor(MenuType menu_type, const gfx::Rect& bounds) { + uint32_t anchor = 0; + switch (menu_type) { + case MenuType::TYPE_RIGHT_CLICK: + anchor = ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT; + break; + case MenuType::TYPE_3DOT_PARENT_MENU: + anchor = + ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT; + break; + case MenuType::TYPE_3DOT_CHILD_MENU: + anchor = ZXDG_POSITIONER_V6_ANCHOR_TOP; + // Chromium may want to manually position a child menu on the left side of + // its parent menu. Thus, react accordingly. Positive x means the child is + // located on the right side of the parent and negative - on the left + // side. + if (bounds.x() >= 0) + anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT; + else + anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; + break; + case MenuType::TYPE_UNKNOWN: + NOTREACHED() << "Unsupported menu type"; + break; + } + + return anchor; +} + +uint32_t GetGravity(MenuType menu_type, const gfx::Rect& bounds) { + uint32_t gravity = 0; + switch (menu_type) { + case MenuType::TYPE_RIGHT_CLICK: + gravity = + ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT; + break; + case MenuType::TYPE_3DOT_PARENT_MENU: + gravity = + ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT; + break; + case MenuType::TYPE_3DOT_CHILD_MENU: + gravity = ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; + // Chromium may want to manually position a child menu on the left side of + // its parent menu. Thus, react accordingly. Positive x means the child is + // located on the right side of the parent and negative - on the left + // side. + if (bounds.x() >= 0) + gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT; + else + gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; + break; + case MenuType::TYPE_UNKNOWN: + NOTREACHED() << "Unsupported menu type"; + break; + } + + return gravity; +} + +uint32_t GetConstraintAdjustment(MenuType menu_type) { + uint32_t constraint = 0; + + switch (menu_type) { + case MenuType::TYPE_RIGHT_CLICK: + constraint = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y; + break; + case MenuType::TYPE_3DOT_PARENT_MENU: + constraint = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y; + break; + case MenuType::TYPE_3DOT_CHILD_MENU: + constraint = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + break; + case MenuType::TYPE_UNKNOWN: + NOTREACHED() << "Unsupported menu type"; + break; + } + + return constraint; +} + +gfx::Rect GetAnchorRect(MenuType menu_type, + const gfx::Rect& menu_bounds, + const gfx::Rect& parent_window_bounds) { + gfx::Rect anchor_rect; + switch (menu_type) { + case MenuType::TYPE_RIGHT_CLICK: + // Place anchor for right click menus normally. + anchor_rect = gfx::Rect(menu_bounds.x(), menu_bounds.y(), + kAnchorDefaultWidth, kAnchorDefaultHeight); + break; + case MenuType::TYPE_3DOT_PARENT_MENU: + // The anchor for parent menu windows is positioned slightly above the + // specified bounds to ensure flipped window along y-axis won't hide 3-dot + // menu button. + anchor_rect = gfx::Rect(menu_bounds.x() - kAnchorDefaultWidth, + menu_bounds.y() - kAnchorHeightParentMenu, + kAnchorDefaultWidth, kAnchorHeightParentMenu); + break; + case MenuType::TYPE_3DOT_CHILD_MENU: + // The child menu's anchor must meet the following requirements: at some + // point, the Wayland compositor can flip it along x-axis. To make sure + // it's positioned correctly, place it closer to the beginning of the + // parent menu shifted by the same value along x-axis. The width of anchor + // must correspond the width between two points - specified origin by the + // Chromium and calculated point shifted by the same value along x-axis + // from the beginning of the parent menu width. + // + // We also have to bear in mind that Chromium may decide to flip the + // position of the menu window along the x-axis and show it on the other + // side of the parent menu window (normally, the Wayland compositor does + // it). Thus, check which side the child menu window is going to be + // presented on and create right anchor. + if (menu_bounds.x() >= 0) { + auto anchor_width = + parent_window_bounds.width() - + (parent_window_bounds.width() - menu_bounds.x()) * 2; + anchor_rect = + gfx::Rect(parent_window_bounds.width() - menu_bounds.x(), + menu_bounds.y(), anchor_width, kAnchorDefaultHeight); + } else { + DCHECK_LE(menu_bounds.x(), 0); + auto position = menu_bounds.width() + menu_bounds.x(); + DCHECK(position > 0 && position < parent_window_bounds.width()); + auto anchor_width = parent_window_bounds.width() - position * 2; + anchor_rect = gfx::Rect(position, menu_bounds.y(), anchor_width, + kAnchorDefaultHeight); + } + break; + case MenuType::TYPE_UNKNOWN: + NOTREACHED() << "Unsupported menu type"; + break; + } + + return anchor_rect; +} + +} // namespace + XDGPopupWrapperV6::XDGPopupWrapperV6(std::unique_ptr<XDGSurfaceWrapper> surface, WaylandWindow* wayland_window) : wayland_window_(wayland_window), zxdg_surface_v6_(std::move(surface)) { @@ -51,7 +208,8 @@ if (!parent_xdg_surface) return false; - zxdg_positioner_v6* positioner = CreatePositioner(connection, bounds); + zxdg_positioner_v6* positioner = + CreatePositioner(connection, parent_window, bounds); if (!positioner) return false; @@ -73,20 +231,41 @@ zxdg_positioner_v6* XDGPopupWrapperV6::CreatePositioner( WaylandConnection* connection, + WaylandWindow* parent_window, const gfx::Rect& bounds) { struct zxdg_positioner_v6* positioner; positioner = zxdg_shell_v6_create_positioner(connection->shell_v6()); if (!positioner) return nullptr; - zxdg_positioner_v6_set_anchor_rect(positioner, bounds.x(), bounds.y(), 1, 1); + auto* pointer = connection->pointer(); + uint32_t flags = 0; + if (pointer) + flags = pointer->GetFlagsWithKeyboardModifiers(); + bool is_right_click_menu = flags & EF_RIGHT_MOUSE_BUTTON; + + // Different types of menu require different anchors, constraint adjustments, + // gravity and etc. + MenuType menu_type = MenuType::TYPE_UNKNOWN; + if (is_right_click_menu) + menu_type = MenuType::TYPE_RIGHT_CLICK; + else if (parent_window->xdg_popup()) + menu_type = MenuType::TYPE_3DOT_CHILD_MENU; + else + menu_type = MenuType::TYPE_3DOT_PARENT_MENU; + + // Place anchor to the end of the possible position. + gfx::Rect anchor_rect = + GetAnchorRect(menu_type, bounds, parent_window->GetBounds()); + + zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(), + anchor_rect.y(), anchor_rect.width(), + anchor_rect.height()); zxdg_positioner_v6_set_size(positioner, bounds.width(), bounds.height()); - zxdg_positioner_v6_set_anchor( - positioner, - ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT); - zxdg_positioner_v6_set_gravity( - positioner, - ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT); + zxdg_positioner_v6_set_anchor(positioner, GetAnchor(menu_type, bounds)); + zxdg_positioner_v6_set_gravity(positioner, GetGravity(menu_type, bounds)); + zxdg_positioner_v6_set_constraint_adjustment( + positioner, GetConstraintAdjustment(menu_type)); return positioner; } @@ -96,7 +275,19 @@ int32_t x, int32_t y, int32_t width, - int32_t height) {} + int32_t height) { + // As long as the Wayland compositor repositions/requires to position windows + // relative to their parents, do not propagate final bounds information to + // Chromium. The browser places windows in respect to screen origin, but + // Wayland requires doing so in respect to parent window's origin. To properly + // place windows, the bounds are translated and adjusted according to the + // Wayland compositor needs during WaylandWindow::CreateXdgPopup call. + gfx::Rect new_bounds(x, y, width, height); + WaylandWindow* window = + static_cast<XDGPopupWrapperV6*>(data)->wayland_window_; + DCHECK(window); + window->HandlePopupConfigure(new_bounds); +} // static void XDGPopupWrapperV6::PopupDone(void* data,
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h index b3df086..4e43d2dd 100644 --- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h +++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
@@ -26,6 +26,7 @@ const gfx::Rect& bounds) override; zxdg_positioner_v6* CreatePositioner(WaylandConnection* connection, + WaylandWindow* parent_window, const gfx::Rect& bounds); // xdg_popup_listener
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index 7bb14468..c27df5f 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -66,7 +66,6 @@ ? Widget::InitParams::TRANSLUCENT_WINDOW : Widget::InitParams::OPAQUE_WINDOW; bubble_params.accept_events = bubble->accept_events(); - bubble_params.remove_standard_frame = true; // Use a window default shadow if the bubble doesn't provides its own. if (bubble->GetShadow() == BubbleBorder::NO_ASSETS) bubble_params.shadow_type = Widget::InitParams::SHADOW_TYPE_DEFAULT; @@ -153,8 +152,10 @@ std::unique_ptr<BubbleBorder> border = std::make_unique<BubbleBorder>(adjusted_arrow, GetShadow(), color()); if (CustomShadowsSupported() && ShouldHaveRoundCorners()) { - const int corner_radius = provider->GetCornerRadiusMetric(EMPHASIS_HIGH); - border->SetCornerRadius(corner_radius); + // TODO(sajadm): Remove when fixing https://crbug.com/822075 and use + // EMPHASIS_HIGH metric values from the LayoutProvider to get the + // corner radius. + border->SetCornerRadius(2); } frame->SetBubbleBorder(std::move(border));
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc index 71a4d87..c5e4525 100644 --- a/ui/views/controls/webview/webview.cc +++ b/ui/views/controls/webview/webview.cc
@@ -16,7 +16,6 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "ipc/ipc_message.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/events/event.h" @@ -261,26 +260,11 @@ } gfx::NativeViewAccessible WebView::GetNativeViewAccessible() { - // On Windows, when UI Automation is enabled, we do not link to the render - // widget's NativeViewAccessible here. UIA recognizes the HWND parent-child - // relationship between the browser UI HWND and the LegacyRenderWidgetHostHWND - // associated with the render widget. By default, it assumes that HWND - // parent-child relationships map to accessibility parent-child relationships. - // - // If we were to return the render widget's NativeViewAccessible here, the - // browser content accessibility tree would appear rooted in two places: (1) - // in the UI widget hierarchy at the WebView's position, and (2) as a direct - // child of the browser UI fragment root, owing to the HWND parent-child - // relationship between the browser UI HWND and LegacyRenderWidgetHostHWND. - // That would lead to tree navigation inconsistencies that confuse assistive - // technologies such as Narrator. - if (!::switches::IsExperimentalAccessibilityPlatformUIAEnabled()) { - if (web_contents() && !web_contents()->IsCrashed()) { - content::RenderWidgetHostView* host_view = - web_contents()->GetRenderWidgetHostView(); - if (host_view) - return host_view->GetNativeViewAccessible(); - } + if (web_contents() && !web_contents()->IsCrashed()) { + content::RenderWidgetHostView* host_view = + web_contents()->GetRenderWidgetHostView(); + if (host_view) + return host_view->GetNativeViewAccessible(); } return View::GetNativeViewAccessible(); }
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index 887cfbd3..dd9210c 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -25,6 +25,7 @@ #include "ui/events/gestures/gesture_recognizer_observer.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/vector2d_conversions.h" +#include "ui/gfx/image/image_skia_operations.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/corewm/tooltip_aura.h" #include "ui/views/mus/cursor_manager_owner.h" @@ -345,11 +346,6 @@ SetBoundsInDIP(params.bounds); } - // If the standard frame is not used, the frame area (rendered by the client) - // should be handled by the client, so it shouldn't update the client area - // by itself. See https://crbug.com/935338. - auto_update_client_area_ = !params.remove_standard_frame; - cursor_manager_owner_ = std::make_unique<CursorManagerOwner>(window()); InitHost(); @@ -897,7 +893,20 @@ void DesktopWindowTreeHostMus::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { - NativeWidgetAura::AssignIconToAuraWindow(window(), window_icon, app_icon); + // In Ash, the app icon is always used in preference to the window icon, so + // ignore the window icon. The max size that ash needs is 24dip, which is + // kIconSize in caption_container_view.cc. + constexpr gfx::Size kMaxUsefulAppIconSize(24, 24); + DCHECK_EQ(app_icon.width(), app_icon.height()); + gfx::ImageSkia app_icon_resized = + app_icon.width() > kMaxUsefulAppIconSize.width() + ? gfx::ImageSkiaOperations::CreateResizedImage( + app_icon, skia::ImageOperations::RESIZE_BEST, + kMaxUsefulAppIconSize) + : app_icon; + + window()->GetRootWindow()->SetProperty(aura::client::kAppIconSmallKey, + new gfx::ImageSkia(app_icon_resized)); } void DesktopWindowTreeHostMus::InitModalType(ui::ModalType modal_type) { @@ -1032,7 +1041,7 @@ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) { gfx::Rect final_bounds = bounds; // If the server initiated the bounds change, then we need to honor it. - if (!in_set_bounds_from_server() && bounds_in_dip().size() != bounds.size()) { + if (!is_server_setting_bounds() && bounds_in_dip().size() != bounds.size()) { gfx::Size size = bounds.size(); size.SetToMax(native_widget_delegate_->GetMinimumSize()); const gfx::Size max_size = native_widget_delegate_->GetMaximumSize(); @@ -1051,7 +1060,7 @@ // WindowTreeHost exposes SetBoundsInPixels() this function may be called too. // If the server initiated the bounds change, then we need to honor it. gfx::Rect final_bounds_in_pixels = bounds_in_pixels; - if (!in_set_bounds_from_server() && + if (!is_server_setting_bounds() && GetBoundsInPixels().size() != bounds_in_pixels.size()) { gfx::Size size = bounds_in_pixels.size(); size.SetToMax(gfx::ConvertSizeToPixel(
diff --git a/ui/views/mus/desktop_window_tree_host_mus.h b/ui/views/mus/desktop_window_tree_host_mus.h index 5df1a1cd..56cea18 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.h +++ b/ui/views/mus/desktop_window_tree_host_mus.h
@@ -40,6 +40,11 @@ // Called when the window was deleted on the server. void ServerDestroyedWindow() { CloseNow(); } + // Controls whether the client area is automatically updated as necessary. + void set_auto_update_client_area(bool value) { + auto_update_client_area_ = value; + } + private: class WindowTreeHostWindowObserver;
diff --git a/ui/views/mus/mus_client.cc b/ui/views/mus/mus_client.cc index 56c57cf3..ad63c545 100644 --- a/ui/views/mus/mus_client.cc +++ b/ui/views/mus/mus_client.cc
@@ -246,22 +246,6 @@ mojo::ConvertTo<TransportType>( init_params.delegate->GetWindowTitle()); } - - // TODO(crbug.com/667566): Support additional scales or gfx::Image[Skia]. - gfx::ImageSkia app_icon = init_params.delegate->GetWindowAppIcon(); - SkBitmap app_bitmap = app_icon.GetRepresentation(1.f).GetBitmap(); - if (!app_bitmap.isNull()) { - properties[WindowManager::kAppIcon_Property] = - mojo::ConvertTo<TransportType>(app_bitmap); - } - - // TODO(crbug.com/667566): Support additional scales or gfx::Image[Skia]. - gfx::ImageSkia window_icon = init_params.delegate->GetWindowIcon(); - SkBitmap window_bitmap = window_icon.GetRepresentation(1.f).GetBitmap(); - if (!window_bitmap.isNull()) { - properties[WindowManager::kWindowIcon_Property] = - mojo::ConvertTo<TransportType>(window_bitmap); - } } return properties;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 79fccf5..c98222f8 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -792,8 +792,8 @@ // platform code might show the desktop window tree host early, meaning we // aren't fully visible as we haven't shown the content window. Callers may // short-circuit a call to show this widget if they think its already visible. - return content_window_ && content_window_->IsVisible() && - desktop_window_tree_host_->IsVisible(); + return content_window_ && content_window_->TargetVisibility() && + desktop_window_tree_host_->IsVisible(); } void DesktopNativeWidgetAura::Activate() {
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index 1a540cc..55b8c93 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -16,6 +16,7 @@ #include "base/timer/timer.h" #include "base/win/windows_version.h" #include "build/build_config.h" +#include "ui/aura/window.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/text_input_client.h" #include "ui/base/resource/resource_bundle.h" @@ -41,7 +42,6 @@ #include "ui/wm/public/activation_client.h" #if defined(OS_WIN) -#include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/win/hwnd_util.h" @@ -1419,38 +1419,32 @@ } #if defined(OS_WIN) -// Tests that widget visibility toggles correctly when minimized and maximized -// on Windows. Test using both the widget API as well as native win32 functions -// that operate directly on the underlying HWND. Behavior should be the same. +// TODO(davidbienvenu): Get this test to pass on Linux and ChromeOS by hiding +// the root window when desktop widget is minimized. +// Tests that root window visibility toggles correctly when the desktop widget +// is minimized and maximized on Windows, and the Widget remains visible. TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) { Widget* widget = CreateWidget(); + aura::Window* root_window = GetRootWindow(widget); ShowSync(widget); ASSERT_FALSE(widget->IsMinimized()); + EXPECT_TRUE(root_window->IsVisible()); PropertyWaiter minimize_widget_waiter( - base::Bind(&Widget::IsMinimized, base::Unretained(widget)), true); + base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)), + true); widget->Minimize(); EXPECT_TRUE(minimize_widget_waiter.Wait()); - EXPECT_FALSE(widget->IsVisible()); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_FALSE(root_window->IsVisible()); PropertyWaiter restore_widget_waiter( - base::Bind(&Widget::IsMinimized, base::Unretained(widget)), false); + base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)), + false); widget->Restore(); EXPECT_TRUE(restore_widget_waiter.Wait()); EXPECT_TRUE(widget->IsVisible()); - - PropertyWaiter minimize_hwnd_waiter( - base::Bind(&Widget::IsMinimized, base::Unretained(widget)), true); - CloseWindow(HWNDForWidget(widget)); - EXPECT_TRUE(minimize_hwnd_waiter.Wait()); - EXPECT_FALSE(widget->IsVisible()); - - PropertyWaiter restore_hwnd_waiter( - base::Bind(&Widget::IsMinimized, base::Unretained(widget)), false); - OpenIcon(HWNDForWidget(widget)); - EXPECT_TRUE(restore_hwnd_waiter.Wait()); - EXPECT_TRUE(widget->IsVisible()); - + EXPECT_TRUE(root_window->IsVisible()); widget->CloseNow(); } #endif // defined(OS_WIN)
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc index 3060b8b..3c706c8 100644 --- a/ui/views/window/dialog_delegate.cc +++ b/ui/views/window/dialog_delegate.cc
@@ -220,8 +220,10 @@ DialogDelegate* delegate = widget->widget_delegate()->AsDialogDelegate(); if (delegate) { if (delegate->ShouldHaveRoundCorners()) { - const int corner_radius = provider->GetCornerRadiusMetric(EMPHASIS_HIGH); - border->SetCornerRadius(corner_radius); + // TODO(sajadm): Remove when fixing https://crbug.com/822075 and use + // EMPHASIS_HIGH metric values from the LayoutProvider to get the + // corner radius. + border->SetCornerRadius(2); } frame->SetFootnoteView(delegate->CreateFootnoteView()); }
diff --git a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html index 32cb0875..df88d87 100644 --- a/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html +++ b/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html
@@ -10,7 +10,7 @@ <template> <style> :host { - --avatar-size: 48px; + --avatar-size: 96px; --avatar-spacing: 24px; display: inline-flex; @@ -22,7 +22,7 @@ background-position: center; background-repeat: no-repeat; border: 1px solid rgba(0, 0, 0, .12); - border-radius: var(--cr-card-border-radius); + border-radius: 100%; display: flex; height: var(--avatar-size); margin: calc(var(--avatar-spacing) / 2); @@ -41,6 +41,10 @@ border: 2px solid var(--google-blue-500); } + paper-button { + background-size: var(--avatar-size); + } + :host-context([dark]) #avatar-grid .avatar.iron-selected { border-color: var(--google-blue-refresh-300); }