diff --git a/DEPS b/DEPS index 07393db..6db9840 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '0122af08f6af0dee490e1a4f35b552377d0d4753', + 'skia_revision': 'dc87c95382d5beab7fdae2e654d6de568fbe1671', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '75378bf9b92ebcd66c37f4b621ae4cd1c0c23b5d', + 'v8_revision': '632d0542e57d2553c73892e4f45fd442f155e256', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -60,11 +60,11 @@ # 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': 'dc7759ccc3151a1aefefa9f86610e66f6fe9311c', + 'swiftshader_revision': '35e0ba7753cab88905b428b65577669620798507', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '66568bcd683dd7b18672cb3aebca4487e9203519', + 'pdfium_revision': '60cd033adf6c469ff47bdaf85a66b5817fdd188b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,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': '5fa840e82c50ff0ab1c9b0a7ee211d3c88f416d4', + 'catapult_revision': 'fa1d11d0530dd5eb7992dd7e599e6b9908afe8c7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -244,7 +244,7 @@ Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248 'src/third_party/libyuv': - Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'fc02cc3806a394a6b887979ba74aa49955f3199b', # from r1652 + Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '3b583396bf138334e90e06ad901f73589a929474', # from r1652 'src/third_party/smhasher/src': Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f', @@ -1152,6 +1152,15 @@ 'src/third_party/gvr-android-sdk/test-apks/update.py', ], }, + + # Download Telemetry's binary dependencies + { + 'name': 'fetch_telemetry_binary_dependencies', + 'pattern': '.', + 'action': [ 'python', + 'src/third_party/catapult/telemetry/bin/fetch_telemetry_binary_dependencies', + ], + }, ] recursedeps = [
diff --git a/ash/aura/shell_port_classic.cc b/ash/aura/shell_port_classic.cc index 766ae12..d2eaa4b6 100644 --- a/ash/aura/shell_port_classic.cc +++ b/ash/aura/shell_port_classic.cc
@@ -42,6 +42,7 @@ #if defined(USE_X11) #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h" +#include "ui/display/manager/chromeos/x11/native_display_delegate_x11.h" #endif #if defined(USE_OZONE) @@ -267,7 +268,7 @@ #if defined(USE_OZONE) return ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(); #else - return nullptr; + return base::MakeUnique<display::NativeDisplayDelegateX11>(); #endif }
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc index 55670a9..914eb82 100644 --- a/ash/display/mirror_window_controller.cc +++ b/ash/display/mirror_window_controller.cc
@@ -173,13 +173,20 @@ mirroring_host_info_map_.end()) { AshWindowTreeHostInitParams init_params; init_params.initial_bounds = display_info.bounds_in_native(); + init_params.display_id = display_info.id(); + init_params.device_scale_factor = display_info.device_scale_factor(); + init_params.ui_scale_factor = display_info.configured_ui_scale(); MirroringHostInfo* host_info = new MirroringHostInfo; host_info->ash_host = AshWindowTreeHost::Create(init_params); mirroring_host_info_map_[display_info.id()] = host_info; aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost(); - host->SetSharedInputMethod( - Shell::Get()->window_tree_host_manager()->input_method()); + // TODO: Config::MUS should not install an InputMethod. + // http://crbug.com/706913 + if (!host->has_input_method()) { + host->SetSharedInputMethod( + Shell::Get()->window_tree_host_manager()->input_method()); + } host->window()->SetName( base::StringPrintf("MirrorRootWindow-%d", mirror_host_count++)); host->compositor()->SetBackgroundColor(SK_ColorBLACK); @@ -222,13 +229,17 @@ mirror_window->Show(); if (reflector_) { reflector_->AddMirroringLayer(mirror_window->layer()); - } else { + } else if (aura::Env::GetInstance()->context_factory_private()) { reflector_ = aura::Env::GetInstance() ->context_factory_private() ->CreateReflector( Shell::GetPrimaryRootWindow()->GetHost()->compositor(), mirror_window->layer()); + } else { + // TODO: Config::MUS needs to support reflector. + // http://crbug.com/601869. + NOTIMPLEMENTED(); } } else { AshWindowTreeHost* ash_host = @@ -294,7 +305,10 @@ if (info->mirror_window_host_size == host->GetBoundsInPixels().size()) return; info->mirror_window_host_size = host->GetBoundsInPixels().size(); - reflector_->OnMirroringCompositorResized(); + // TODO: |reflector_| should always be non-null here, but isn't in MUS + // yet because of http://crbug.com/601869. + if (reflector_) + reflector_->OnMirroringCompositorResized(); // No need to update the transformer as new transformer is already set // in UpdateWindow. Shell::Get() @@ -362,7 +376,10 @@ host->RemoveObserver(Shell::Get()->window_tree_host_manager()); host->RemoveObserver(this); host_info->ash_host->PrepareForShutdown(); - reflector_->RemoveMirroringLayer(host_info->mirror_window->layer()); + // TODO: |reflector_| should always be non-null here, but isn't in MUS yet + // because of http://crbug.com/601869. + if (reflector_) + reflector_->RemoveMirroringLayer(host_info->mirror_window->layer()); // EventProcessor may be accessed after this call if the mirroring window // was deleted as a result of input event (e.g. shortcut), so don't delete
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc index 7f11547..bce98e78 100644 --- a/ash/display/window_tree_host_manager.cc +++ b/ash/display/window_tree_host_manager.cc
@@ -524,7 +524,9 @@ // The cursor's native position did not change but its screen position did // change. This occurs when the scale factor or the rotation of the display // that the cursor is on changes. - Shell::Get()->cursor_manager()->SetDisplay(target_display); + // TODO: conditional should not be necessary. http://crbug.com/631103. + if (Shell::Get()->cursor_manager()) + Shell::Get()->cursor_manager()->SetDisplay(target_display); // Update the cursor's root location. This ends up dispatching a synthetic // mouse move. The synthetic mouse move updates the composited cursor's @@ -813,22 +815,29 @@ params_with_bounds.initial_bounds = display_info.bounds_in_native(); params_with_bounds.offscreen = display.id() == display::DisplayManager::kUnifiedDisplayId; + params_with_bounds.display_id = display.id(); + params_with_bounds.device_scale_factor = display.device_scale_factor(); + params_with_bounds.ui_scale_factor = display_info.configured_ui_scale(); // The AshWindowTreeHost ends up owned by the RootWindowControllers created // by this class. AshWindowTreeHost* ash_host = AshWindowTreeHost::Create(params_with_bounds).release(); aura::WindowTreeHost* host = ash_host->AsWindowTreeHost(); - if (!input_method_) { // Singleton input method instance for Ash. - input_method_ = ui::CreateInputMethod(this, host->GetAcceleratedWidget()); - // Makes sure the input method is focused by default when created, because - // Ash uses singleton InputMethod and it won't call OnFocus/OnBlur when the - // active window changed. - input_method_->OnFocus(); - input_method_event_handler_.reset( - new InputMethodEventHandler(input_method_.get())); + // TODO: Config::MUS should not install an InputMethod. + // http://crbug.com/706913 + if (!host->has_input_method()) { + if (!input_method_) { // Singleton input method instance for Ash. + input_method_ = ui::CreateInputMethod(this, host->GetAcceleratedWidget()); + // Makes sure the input method is focused by default when created, because + // Ash uses singleton InputMethod and it won't call OnFocus/OnBlur when + // the active window changed. + input_method_->OnFocus(); + input_method_event_handler_.reset( + new InputMethodEventHandler(input_method_.get())); + } + host->SetSharedInputMethod(input_method_.get()); + ash_host->set_input_method_handler(input_method_event_handler_.get()); } - host->SetSharedInputMethod(input_method_.get()); - ash_host->set_input_method_handler(input_method_event_handler_.get()); host->window()->SetName(base::StringPrintf( "%sRootWindow-%d", params_with_bounds.offscreen ? "Offscreen" : "",
diff --git a/ash/host/transformer_helper.h b/ash/host/transformer_helper.h index cd8f998..70db3039 100644 --- a/ash/host/transformer_helper.h +++ b/ash/host/transformer_helper.h
@@ -7,6 +7,7 @@ #include <memory> +#include "ash/ash_export.h" #include "base/macros.h" namespace gfx { @@ -21,7 +22,7 @@ // A helper class to handle ash specific feature that requires // transforming a root window (such as rotation, UI zooming). -class TransformerHelper { +class ASH_EXPORT TransformerHelper { public: explicit TransformerHelper(AshWindowTreeHost* ash_host); ~TransformerHelper();
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn index c2ed127..605d8dd 100644 --- a/ash/mus/BUILD.gn +++ b/ash/mus/BUILD.gn
@@ -20,6 +20,8 @@ "accelerators/accelerator_ids.h", "accessibility_delegate_mus.cc", "accessibility_delegate_mus.h", + "ash_window_tree_host_mus.cc", + "ash_window_tree_host_mus.h", "bridge/immersive_handler_factory_mus.cc", "bridge/immersive_handler_factory_mus.h", "bridge/shell_port_mash.cc",
diff --git a/ash/mus/DEPS b/ash/mus/DEPS index 20c5578..04115d1 100644 --- a/ash/mus/DEPS +++ b/ash/mus/DEPS
@@ -12,6 +12,10 @@ ] specific_include_rules = { + "ash_window_tree_host_mus\.*": [ + "+ash/host", + ], + "app_launch_unittest.cc": [ "+mash/quick_launch/public", ],
diff --git a/ash/mus/ash_window_tree_host_mus.cc b/ash/mus/ash_window_tree_host_mus.cc new file mode 100644 index 0000000..52cb894 --- /dev/null +++ b/ash/mus/ash_window_tree_host_mus.cc
@@ -0,0 +1,87 @@ +// 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 "ash/mus/ash_window_tree_host_mus.h" + +#include "ash/host/root_window_transformer.h" +#include "ash/host/transformer_helper.h" +#include "base/memory/ptr_util.h" +#include "ui/aura/mus/window_tree_host_mus_init_params.h" +#include "ui/aura/window.h" +#include "ui/events/null_event_targeter.h" + +namespace ash { + +AshWindowTreeHostMus::AshWindowTreeHostMus( + aura::WindowTreeHostMusInitParams init_params) + : aura::WindowTreeHostMus(std::move(init_params)), + transformer_helper_(base::MakeUnique<TransformerHelper>(this)) { + transformer_helper_->Init(); +} + +AshWindowTreeHostMus::~AshWindowTreeHostMus() {} + +void AshWindowTreeHostMus::ToggleFullScreen() { + NOTIMPLEMENTED(); +} + +bool AshWindowTreeHostMus::ConfineCursorToRootWindow() { + // TODO: when implementing see implementation in AshWindowTreeHostPlatform + // for how it uses |transformer_helper_|. + NOTIMPLEMENTED(); + return true; +} + +void AshWindowTreeHostMus::UnConfineCursor() { + NOTIMPLEMENTED(); +} + +void AshWindowTreeHostMus::SetRootWindowTransformer( + std::unique_ptr<RootWindowTransformer> transformer) { + transformer_helper_->SetRootWindowTransformer(std::move(transformer)); + ConfineCursorToRootWindow(); +} + +gfx::Insets AshWindowTreeHostMus::GetHostInsets() const { + return transformer_helper_->GetHostInsets(); +} + +aura::WindowTreeHost* AshWindowTreeHostMus::AsWindowTreeHost() { + return this; +} + +void AshWindowTreeHostMus::PrepareForShutdown() { + // WindowEventDispatcher may have pending events that need to be processed. + // At the time this function is called the WindowTreeHost and Window are in + // a semi-shutdown state. Reset the targeter so that the current targeter + // doesn't attempt to process events while in this state, which would likely + // crash. + std::unique_ptr<ui::NullEventTargeter> null_event_targeter = + base::MakeUnique<ui::NullEventTargeter>(); + window()->SetEventTargeter(std::move(null_event_targeter)); +} + +void AshWindowTreeHostMus::RegisterMirroringHost( + AshWindowTreeHost* mirroring_ash_host) { + NOTIMPLEMENTED(); +} + +void AshWindowTreeHostMus::SetRootTransform(const gfx::Transform& transform) { + transformer_helper_->SetTransform(transform); +} + +gfx::Transform AshWindowTreeHostMus::GetRootTransform() const { + return transformer_helper_->GetTransform(); +} + +gfx::Transform AshWindowTreeHostMus::GetInverseRootTransform() const { + return transformer_helper_->GetInverseTransform(); +} + +void AshWindowTreeHostMus::UpdateRootWindowSizeInPixels( + const gfx::Size& host_size_in_pixels) { + transformer_helper_->UpdateWindowSize(host_size_in_pixels); +} + +} // namespace ash
diff --git a/ash/mus/ash_window_tree_host_mus.h b/ash/mus/ash_window_tree_host_mus.h new file mode 100644 index 0000000..03056b5 --- /dev/null +++ b/ash/mus/ash_window_tree_host_mus.h
@@ -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. + +#ifndef ASH_MUS_ASH_WINDOW_TREE_HOST_MUS_H_ +#define ASH_MUS_ASH_WINDOW_TREE_HOST_MUS_H_ + +#include "ash/host/ash_window_tree_host.h" +#include "ui/aura/mus/window_tree_host_mus.h" + +namespace ash { + +class TransformerHelper; + +// Implementation of AshWindowTreeHost for mus/mash. +class AshWindowTreeHostMus : public AshWindowTreeHost, + public aura::WindowTreeHostMus { + public: + explicit AshWindowTreeHostMus(aura::WindowTreeHostMusInitParams init_params); + ~AshWindowTreeHostMus() override; + + // AshWindowTreeHost: + void ToggleFullScreen() override; + bool ConfineCursorToRootWindow() override; + void UnConfineCursor() override; + void SetRootWindowTransformer( + std::unique_ptr<RootWindowTransformer> transformer) override; + gfx::Insets GetHostInsets() const override; + aura::WindowTreeHost* AsWindowTreeHost() override; + void PrepareForShutdown() override; + void RegisterMirroringHost(AshWindowTreeHost* mirroring_ash_host) override; + + // aura::WindowTreeHostMus: + void SetRootTransform(const gfx::Transform& transform) override; + gfx::Transform GetRootTransform() const override; + gfx::Transform GetInverseRootTransform() const override; + void UpdateRootWindowSizeInPixels( + const gfx::Size& host_size_in_pixels) override; + + private: + std::unique_ptr<TransformerHelper> transformer_helper_; + + DISALLOW_COPY_AND_ASSIGN(AshWindowTreeHostMus); +}; + +} // namespace ash + +#endif // ASH_MUS_ASH_WINDOW_TREE_HOST_MUS_H_
diff --git a/ash/mus/bridge/shell_port_mash.cc b/ash/mus/bridge/shell_port_mash.cc index c9151d2..a0024c16 100644 --- a/ash/mus/bridge/shell_port_mash.cc +++ b/ash/mus/bridge/shell_port_mash.cc
@@ -10,12 +10,14 @@ #include "ash/accelerators/accelerator_controller_delegate_aura.h" #include "ash/aura/key_event_watcher_aura.h" #include "ash/aura/pointer_watcher_adapter.h" -#include "ash/host/ash_window_tree_host.h" +#include "ash/display/window_tree_host_manager.h" +#include "ash/host/ash_window_tree_host_init_params.h" #include "ash/key_event_watcher.h" #include "ash/laser/laser_pointer_controller.h" #include "ash/magnifier/partial_magnification_controller.h" #include "ash/mus/accelerators/accelerator_controller_delegate_mus.h" #include "ash/mus/accelerators/accelerator_controller_registrar.h" +#include "ash/mus/ash_window_tree_host_mus.h" #include "ash/mus/bridge/immersive_handler_factory_mus.h" #include "ash/mus/bridge/workspace_event_handler_mus.h" #include "ash/mus/drag_window_resizer.h" @@ -50,16 +52,23 @@ #include "ash/wm_window.h" #include "base/memory/ptr_util.h" #include "components/user_manager/user_info_impl.h" +#include "services/ui/public/interfaces/constants.mojom.h" #include "ui/aura/env.h" #include "ui/aura/mus/focus_synchronizer.h" #include "ui/aura/mus/window_tree_client.h" #include "ui/aura/mus/window_tree_host_mus.h" +#include "ui/aura/mus/window_tree_host_mus_init_params.h" #include "ui/aura/window.h" +#include "ui/display/manager/display_manager.h" #include "ui/display/manager/managed_display_info.h" #include "ui/display/screen.h" #include "ui/display/types/native_display_delegate.h" #include "ui/views/mus/pointer_watcher_event_router.h" +#if defined(USE_OZONE) +#include "ui/display/manager/forwarding_display_delegate.h" +#endif + namespace ash { namespace mus { @@ -110,7 +119,6 @@ primary_root_window_(primary_root_window) { if (create_session_state_delegate_stub) session_state_delegate_ = base::MakeUnique<SessionStateDelegateStub>(); - DCHECK(primary_root_window_); if (GetAshConfig() == Config::MASH) { mash_state_ = base::MakeUnique<MashSpecificState>(); @@ -155,7 +163,11 @@ ShellPort::Shutdown(); - window_manager_->DeleteAllRootWindowControllers(); + // TODO(sky): Config::MASH should use WindowTreeHostManager too. + if (GetAshConfig() == Config::MUS) + Shell::Get()->window_tree_host_manager()->Shutdown(); + else + window_manager_->DeleteAllRootWindowControllers(); } Config ShellPortMash::GetAshConfig() const { @@ -163,12 +175,21 @@ } WmWindow* ShellPortMash::GetPrimaryRootWindow() { + if (GetAshConfig() == Config::MUS) { + return WmWindow::Get( + Shell::Get()->window_tree_host_manager()->GetPrimaryRootWindow()); + } // NOTE: This is called before the RootWindowController has been created, so // it can't call through to RootWindowController to get all windows. return primary_root_window_; } WmWindow* ShellPortMash::GetRootWindowForDisplayId(int64_t display_id) { + if (GetAshConfig() == Config::MUS) { + return WmWindow::Get( + Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId( + display_id)); + } RootWindowController* root_window_controller = GetRootWindowControllerWithDisplayId(display_id); return root_window_controller @@ -210,6 +231,12 @@ void ShellPortMash::SetDisplayWorkAreaInsets(WmWindow* window, const gfx::Insets& insets) { + if (GetAshConfig() == Config::MUS) { + Shell::Get() + ->window_tree_host_manager() + ->UpdateWorkAreaOfDisplayNearestWindow(window->aura_window(), insets); + return; + } window_manager_->screen()->SetWorkAreaInsets(window->aura_window(), insets); } @@ -230,6 +257,14 @@ } std::vector<WmWindow*> ShellPortMash::GetAllRootWindows() { + if (GetAshConfig() == Config::MUS) { + aura::Window::Windows root_windows = + Shell::Get()->window_tree_host_manager()->GetAllRootWindows(); + std::vector<WmWindow*> wm_windows(root_windows.size()); + for (size_t i = 0; i < root_windows.size(); ++i) + wm_windows[i] = WmWindow::Get(root_windows[i]); + return wm_windows; + } std::vector<WmWindow*> root_windows; for (RootWindowController* root_window_controller : RootWindowController::root_window_controllers()) { @@ -429,7 +464,32 @@ std::unique_ptr<AshWindowTreeHost> ShellPortMash::CreateAshWindowTreeHost( const AshWindowTreeHostInitParams& init_params) { - return nullptr; + // TODO(sky): make this work for mash too. + if (GetAshConfig() != Config::MUS) + return nullptr; + + std::unique_ptr<aura::DisplayInitParams> display_params = + base::MakeUnique<aura::DisplayInitParams>(); + display_params->viewport_metrics.bounds_in_pixels = + init_params.initial_bounds; + display_params->viewport_metrics.device_scale_factor = + init_params.device_scale_factor; + display_params->viewport_metrics.ui_scale_factor = + init_params.ui_scale_factor; + display::Display mirrored_display = + Shell::Get()->display_manager()->GetMirroringDisplayById( + init_params.display_id); + if (mirrored_display.is_valid()) { + display_params->display = + base::MakeUnique<display::Display>(mirrored_display); + } + // TODO: wire update is_primary_display correctly. + display_params->is_primary_display = true; + aura::WindowTreeHostMusInitParams aura_init_params = + window_manager_->window_manager_client()->CreateInitParamsForNewDisplay(); + aura_init_params.display_id = init_params.display_id; + aura_init_params.display_init_params = std::move(display_params); + return base::MakeUnique<AshWindowTreeHostMus>(std::move(aura_init_params)); } void ShellPortMash::OnCreatedRootWindowContainers( @@ -443,16 +503,40 @@ } } -void ShellPortMash::CreatePrimaryHost() {} +void ShellPortMash::CreatePrimaryHost() { + if (GetAshConfig() == Config::MASH) + return; + + DCHECK_EQ(Config::MUS, GetAshConfig()); + Shell::Get()->window_tree_host_manager()->Start(); + AshWindowTreeHostInitParams ash_init_params; + Shell::Get()->window_tree_host_manager()->CreatePrimaryHost(ash_init_params); +} void ShellPortMash::InitHosts(const ShellInitParams& init_params) { - window_manager_->CreatePrimaryRootWindowController( - base::WrapUnique(init_params.primary_window_tree_host)); + if (GetAshConfig() == Config::MUS) { + Shell::Get()->window_tree_host_manager()->InitHosts(); + } else { + window_manager_->CreatePrimaryRootWindowController( + base::WrapUnique(init_params.primary_window_tree_host)); + } } std::unique_ptr<display::NativeDisplayDelegate> ShellPortMash::CreateNativeDisplayDelegate() { +#if defined(USE_OZONE) + display::mojom::NativeDisplayDelegatePtr native_display_delegate; + if (window_manager_->connector()) { + window_manager_->connector()->BindInterface(ui::mojom::kServiceName, + &native_display_delegate); + } + return base::MakeUnique<display::ForwardingDisplayDelegate>( + std::move(native_display_delegate)); +#else + // The bots compile this config, but it is never run. + CHECK(false); return nullptr; +#endif } std::unique_ptr<AcceleratorController>
diff --git a/ash/mus/bridge/shell_port_mash.h b/ash/mus/bridge/shell_port_mash.h index 4bee8640..2456370 100644 --- a/ash/mus/bridge/shell_port_mash.h +++ b/ash/mus/bridge/shell_port_mash.h
@@ -140,6 +140,7 @@ WindowManager* window_manager_; + // TODO(sky): remove this once mash supports simple display management. WmWindow* primary_root_window_; // Only one of |mash_state_| or |mus_state_| is created, depending upon
diff --git a/ash/mus/main.cc b/ash/mus/main.cc index e3aa4de..d152d51 100644 --- a/ash/mus/main.cc +++ b/ash/mus/main.cc
@@ -7,6 +7,9 @@ #include "services/service_manager/public/cpp/service_runner.h" MojoResult ServiceMain(MojoHandle service_request_handle) { - service_manager::ServiceRunner runner(new ash::mus::WindowManagerApplication); + const bool show_primary_host_on_connect = true; + ash::mus::WindowManagerApplication* app = + new ash::mus::WindowManagerApplication(show_primary_host_on_connect); + service_manager::ServiceRunner runner(app); return runner.Run(service_request_handle); }
diff --git a/ash/mus/test/ash_test_impl_mus.cc b/ash/mus/test/ash_test_impl_mus.cc index 92e5bb5..b9e5f50f 100644 --- a/ash/mus/test/ash_test_impl_mus.cc +++ b/ash/mus/test/ash_test_impl_mus.cc
@@ -6,10 +6,12 @@ #include "ash/test/ash_test.h" #include "ash/wm_window.h" +#include "base/command_line.h" #include "base/memory/ptr_util.h" #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/window_manager.mojom.h" #include "ui/aura/window.h" +#include "ui/display/display_switches.h" #include "ui/wm/core/window_util.h" namespace ash { @@ -40,6 +42,13 @@ AshTestImplMus::~AshTestImplMus() {} void AshTestImplMus::SetUp() { + // This matches what AshTestBase does. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(::switches::kHostWindowBounds)) { + command_line->AppendSwitchASCII(::switches::kHostWindowBounds, + "1+1-800x600"); + } + wm_test_base_->SetUp(); }
diff --git a/ash/mus/test/wm_test_base.cc b/ash/mus/test/wm_test_base.cc index a777639..eb0979f 100644 --- a/ash/mus/test/wm_test_base.cc +++ b/ash/mus/test/wm_test_base.cc
@@ -7,10 +7,12 @@ #include <algorithm> #include <vector> +#include "ash/display/window_tree_host_manager.h" #include "ash/mus/test/wm_test_helper.h" #include "ash/mus/top_level_window_factory.h" #include "ash/mus/window_manager.h" #include "ash/mus/window_manager_application.h" +#include "ash/public/cpp/config.h" #include "ash/public/cpp/session_types.h" #include "ash/public/interfaces/session_controller.mojom.h" #include "ash/session/session_controller.h" @@ -23,6 +25,7 @@ #include "ui/aura/window.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/display/display.h" +#include "ui/display/manager/display_manager.h" namespace ash { namespace mus { @@ -73,19 +76,26 @@ } aura::Window* WmTestBase::GetPrimaryRootWindow() { - std::vector<RootWindowController*> roots = - test_helper_->GetRootsOrderedByDisplayId(); - DCHECK(!roots.empty()); - return roots[0]->GetRootWindow(); + return Shell::Get()->GetPrimaryRootWindow(); } aura::Window* WmTestBase::GetSecondaryRootWindow() { + if (Shell::GetAshConfig() == Config::MUS) { + return Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId( + GetSecondaryDisplay().id()); + } + std::vector<RootWindowController*> roots = test_helper_->GetRootsOrderedByDisplayId(); return roots.size() < 2 ? nullptr : roots[1]->GetRootWindow(); } display::Display WmTestBase::GetPrimaryDisplay() { + if (Shell::GetAshConfig() == Config::MUS) { + return display::Screen::GetScreen()->GetDisplayNearestWindow( + Shell::Get()->GetPrimaryRootWindow()); + } + std::vector<RootWindowController*> roots = test_helper_->GetRootsOrderedByDisplayId(); DCHECK(!roots.empty()); @@ -93,6 +103,9 @@ } display::Display WmTestBase::GetSecondaryDisplay() { + if (Shell::GetAshConfig() == Config::MUS) + return Shell::Get()->display_manager()->GetSecondaryDisplay(); + std::vector<RootWindowController*> roots = test_helper_->GetRootsOrderedByDisplayId(); return roots.size() < 2 ? display::Display()
diff --git a/ash/mus/test/wm_test_helper.cc b/ash/mus/test/wm_test_helper.cc index 1fd4685..26bb271 100644 --- a/ash/mus/test/wm_test_helper.cc +++ b/ash/mus/test/wm_test_helper.cc
@@ -8,6 +8,7 @@ #include "ash/mus/window_manager.h" #include "ash/mus/window_manager_application.h" #include "ash/public/cpp/config.h" +#include "ash/shell.h" #include "ash/test/test_shell_delegate.h" #include "ash/wm_window.h" #include "base/memory/ptr_util.h" @@ -26,6 +27,7 @@ #include "ui/display/display.h" #include "ui/display/display_list.h" #include "ui/display/screen_base.h" +#include "ui/display/test/display_manager_test_api.h" #include "ui/views/test/test_views_delegate.h" namespace ash { @@ -73,6 +75,11 @@ WmTestHelper::WmTestHelper() {} WmTestHelper::~WmTestHelper() { + // Flush the message loop so that any pending tasks are run. This ensures + // any delayed tasks, such as deleting RootWindowControllers, are processed + // before continuing. + base::RunLoop().RunUntilIdle(); + // Needs to be destroyed before material design. window_manager_app_.reset(); @@ -99,7 +106,9 @@ views_delegate_ = base::MakeUnique<views::TestViewsDelegate>(); - window_manager_app_ = base::MakeUnique<WindowManagerApplication>(); + const bool show_primary_host_on_connect = false; + window_manager_app_ = base::MakeUnique<WindowManagerApplication>( + show_primary_host_on_connect, config); message_loop_.reset(new base::MessageLoopForUI()); @@ -108,8 +117,8 @@ blocking_pool_owner_ = base::MakeUnique<base::SequencedWorkerPoolOwner>( kMaxNumberThreads, kThreadNamePrefix); - window_manager_app_->window_manager_ = - base::MakeUnique<WindowManager>(nullptr, config); + window_manager_app_->window_manager_ = base::MakeUnique<WindowManager>( + nullptr, config, show_primary_host_on_connect); window_manager_app_->window_manager()->shell_delegate_ = base::MakeUnique<test::TestShellDelegate>(); @@ -129,8 +138,12 @@ window_manager_app_->window_manager()->window_tree_client(); window_tree_client_private_ = base::MakeUnique<aura::WindowTreeClientPrivate>(window_tree_client); - int next_x = 0; - CreateRootWindowController("800x600", &next_x); + if (config == Config::MUS) { + window_tree_client_private_->CallOnConnect(); + } else { + int next_x = 0; + CreateRootWindowController("800x600", &next_x); + } } std::vector<RootWindowController*> WmTestHelper::GetRootsOrderedByDisplayId() { @@ -143,6 +156,11 @@ } void WmTestHelper::UpdateDisplay(const std::string& display_spec) { + if (Shell::GetAshConfig() == Config::MUS) { + display::test::DisplayManagerTestApi(Shell::Get()->display_manager()) + .UpdateDisplay(display_spec); + return; + } const std::vector<std::string> parts = base::SplitString( display_spec, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); std::vector<RootWindowController*> root_window_controllers =
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc index 0b7c4ae..b7cf573 100644 --- a/ash/mus/window_manager.cc +++ b/ash/mus/window_manager.cc
@@ -75,9 +75,11 @@ // TODO: need to register OSExchangeDataProviderMus. http://crbug.com/665077. WindowManager::WindowManager(service_manager::Connector* connector, - Config config) + Config config, + bool show_primary_host_on_connect) : connector_(connector), config_(config), + show_primary_host_on_connect_(show_primary_host_on_connect), wm_state_(base::MakeUnique<::wm::WMState>()), property_converter_(base::MakeUnique<aura::PropertyConverter>()) { property_converter_->RegisterProperty( @@ -122,12 +124,14 @@ DCHECK_EQ(nullptr, ash::Shell::window_tree_client()); ash::Shell::set_window_tree_client(window_tree_client_.get()); - // |connector_| will be null in some tests. - if (connector_) - connector_->BindInterface(ui::mojom::kServiceName, &display_controller_); - - screen_ = base::MakeUnique<ScreenMus>(display_controller_.get()); - display::Screen::SetScreenInstance(screen_.get()); + // TODO(sky): remove and use MUS code. + if (config_ == Config::MASH) { + // |connector_| is null in some tests. + if (connector_) + connector_->BindInterface(ui::mojom::kServiceName, &display_controller_); + screen_ = base::MakeUnique<ScreenMus>(display_controller_.get()); + display::Screen::SetScreenInstance(screen_.get()); + } pointer_watcher_event_router_ = base::MakeUnique<views::PointerWatcherEventRouter>( @@ -229,10 +233,10 @@ DCHECK(!created_shell_); created_shell_ = true; ShellInitParams init_params; - ShellPortMash* shell_port = - new ShellPortMash(WmWindow::Get(window_tree_host->window()), this, - pointer_watcher_event_router_.get(), - create_session_state_delegate_stub_for_test_); + ShellPortMash* shell_port = new ShellPortMash( + window_tree_host ? WmWindow::Get(window_tree_host->window()) : nullptr, + this, pointer_watcher_event_router_.get(), + create_session_state_delegate_stub_for_test_); // Shell::CreateInstance() takes ownership of ShellDelegate. init_params.delegate = shell_delegate_ ? shell_delegate_.release() : new ShellDelegateMus(connector_); @@ -336,7 +340,14 @@ ash::Shell::set_window_manager_client(client); } -void WindowManager::OnWmConnected() {} +void WindowManager::OnWmConnected() { + if (config_ != Config::MUS) + return; + + CreateShell(nullptr); + if (show_primary_host_on_connect_) + Shell::GetPrimaryRootWindow()->GetHost()->Show(); +} void WindowManager::OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) {
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h index 8f8631b1..84bb75f6 100644 --- a/ash/mus/window_manager.h +++ b/ash/mus/window_manager.h
@@ -68,7 +68,11 @@ class WindowManager : public aura::WindowManagerDelegate, public aura::WindowTreeClientDelegate { public: - WindowManager(service_manager::Connector* connector, Config config); + // Set |show_primary_host_on_connect| to true if the initial display should + // be made visible. Generally tests should use false, other places use true. + WindowManager(service_manager::Connector* connector, + Config config, + bool show_primary_host_on_connect); ~WindowManager() override; void Init(std::unique_ptr<aura::WindowTreeClient> window_tree_client, @@ -202,6 +206,8 @@ const Config config_; + const bool show_primary_host_on_connect_; + base::OnceClosure lost_connection_callback_; std::unique_ptr<::wm::WMState> wm_state_;
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc index abd098e..416fe37 100644 --- a/ash/mus/window_manager_application.cc +++ b/ash/mus/window_manager_application.cc
@@ -10,6 +10,7 @@ #include "ash/mus/network_connect_delegate_mus.h" #include "ash/mus/window_manager.h" #include "ash/public/cpp/config.h" +#include "ash/shell_delegate.h" #include "ash/system/power/power_status.h" #include "base/bind.h" #include "base/memory/ptr_util.h" @@ -35,9 +36,20 @@ namespace ash { namespace mus { -WindowManagerApplication::WindowManagerApplication() {} +WindowManagerApplication::WindowManagerApplication( + bool show_primary_host_on_connect, + Config ash_config, + std::unique_ptr<ash::ShellDelegate> shell_delegate) + : show_primary_host_on_connect_(show_primary_host_on_connect), + shell_delegate_(std::move(shell_delegate)), + ash_config_(ash_config) {} WindowManagerApplication::~WindowManagerApplication() { + // Verify that we created a WindowManager before attempting to tear everything + // down. In some fast running tests OnStart may never have been called. + if (!window_manager_.get()) + return; + // Destroy the WindowManager while still valid. This way we ensure // OnWillDestroyRootWindowController() is called (if it hasn't been already). window_manager_.reset(); @@ -55,6 +67,10 @@ ShutdownComponents(); } +service_manager::Connector* WindowManagerApplication::GetConnector() { + return context() ? context()->connector() : nullptr; +} + void WindowManagerApplication::InitWindowManager( std::unique_ptr<aura::WindowTreeClient> window_tree_client, const scoped_refptr<base::SequencedWorkerPool>& blocking_pool, @@ -72,7 +88,8 @@ statistics_provider_->SetMachineStatistic("initial_locale", "en-US"); statistics_provider_->SetMachineStatistic("keyboard_layout", ""); - window_manager_->Init(std::move(window_tree_client), blocking_pool); + window_manager_->Init(std::move(window_tree_client), blocking_pool, + std::move(shell_delegate_)); } void WindowManagerApplication::InitializeComponents(bool init_network_handler) { @@ -117,15 +134,18 @@ context()->connector(), context()->identity(), "ash_mus_resources.pak", "ash_mus_resources_200.pak", nullptr, views::AuraInit::Mode::AURA_MUS_WINDOW_MANAGER); - window_manager_ = - base::MakeUnique<WindowManager>(context()->connector(), Config::MASH); + window_manager_ = base::MakeUnique<WindowManager>( + context()->connector(), ash_config_, show_primary_host_on_connect_); tracing_.Initialize(context()->connector(), context()->identity().name()); std::unique_ptr<aura::WindowTreeClient> window_tree_client = base::MakeUnique<aura::WindowTreeClient>( context()->connector(), window_manager_.get(), window_manager_.get()); - window_tree_client->ConnectAsWindowManager(); + const bool automatically_create_display_roots = + window_manager_->config() == Config::MASH; + window_tree_client->ConnectAsWindowManager( + automatically_create_display_roots); const size_t kMaxNumberThreads = 3u; // Matches that of content. const char kThreadNamePrefix[] = "MashBlocking";
diff --git a/ash/mus/window_manager_application.h b/ash/mus/window_manager_application.h index bbab43d..e878d39 100644 --- a/ash/mus/window_manager_application.h +++ b/ash/mus/window_manager_application.h
@@ -10,7 +10,9 @@ #include <memory> #include <set> +#include "ash/public/cpp/config.h" #include "ash/public/interfaces/wallpaper.mojom.h" +#include "ash/shell_delegate.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "mojo/public/cpp/bindings/binding.h" @@ -33,11 +35,16 @@ } } +namespace service_manager { +class Connector; +} + namespace views { class AuraInit; } namespace ash { + namespace test { class AshTestHelper; } @@ -49,11 +56,19 @@ // Hosts the window manager and the ash system user interface for mash. class WindowManagerApplication : public service_manager::Service { public: - WindowManagerApplication(); + // If |observer| is non-null it is added to the WindowManager once created. + // See WindowManager's constructor for details of + // |show_primary_host_on_connect|. + explicit WindowManagerApplication( + bool show_primary_host_on_connect, + Config ash_config = Config::MASH, + std::unique_ptr<ash::ShellDelegate> shell_delegate = nullptr); ~WindowManagerApplication() override; WindowManager* window_manager() { return window_manager_.get(); } + service_manager::Connector* GetConnector(); + private: friend class ash::test::AshTestHelper; friend class WmTestBase; @@ -75,6 +90,8 @@ const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override; + const bool show_primary_host_on_connect_; + tracing::Provider tracing_; std::unique_ptr<views::AuraInit> aura_init_; @@ -90,6 +107,10 @@ service_manager::BinderRegistry registry_; + std::unique_ptr<ShellDelegate> shell_delegate_; + + const Config ash_config_; + DISALLOW_COPY_AND_ASSIGN(WindowManagerApplication); };
diff --git a/ash/shell.cc b/ash/shell.cc index c45bc4aa..8cdfec9 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -154,6 +154,7 @@ #include "ui/display/manager/chromeos/display_configurator.h" #include "ui/display/manager/display_manager.h" #include "ui/display/screen.h" +#include "ui/display/types/native_display_delegate.h" #include "ui/events/event_target_iterator.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/image/image_skia.h" @@ -172,16 +173,6 @@ #include "ui/wm/core/visibility_controller.h" #include "ui/wm/core/window_modality_controller.h" -#if defined(USE_X11) -#include "ui/display/manager/chromeos/x11/native_display_delegate_x11.h" -#include "ui/gfx/x/x11_types.h" // nogncheck -#endif - -#if defined(USE_OZONE) -#include "ui/display/types/native_display_delegate.h" -#include "ui/ozone/public/ozone_platform.h" -#endif - namespace ash { namespace { @@ -579,9 +570,10 @@ // TODO(sky): better refactor cash/mash dependencies. Perhaps put all cash // state on ShellPortClassic. http://crbug.com/671246. + gpu_support_.reset(shell_delegate_->CreateGPUSupport()); + // Don't use Shell::GetAshConfig() as |instance_| has not yet been set. if (shell_port_->GetAshConfig() != Config::MASH) { - gpu_support_.reset(shell_delegate_->CreateGPUSupport()); display_manager_.reset(ScreenAsh::CreateDisplayManager()); window_tree_host_manager_.reset(new WindowTreeHostManager); user_metrics_recorder_.reset(new UserMetricsRecorder); @@ -846,24 +838,20 @@ } shell_delegate_->PreInit(); - bool display_initialized = true; - if (config == Config::CLASSIC) { - // TODO: decide if this needs to be made to work in Config::MUS. - // http://crbug.com/705595. - display_initialized = display_manager_->InitFromCommandLine(); - + // TODO(sky): remove MASH from here. + bool display_initialized = + (config == Config::MASH || display_manager_->InitFromCommandLine()); + if (config == Config::MUS && !display_initialized) { + // Run display configuration off device in mus mode. + display_manager_->set_configure_displays(true); + display_configurator_->set_configure_display(true); + } + if (config != Config::MASH) { + // TODO(sky): should work in mash too. display_configuration_controller_.reset(new DisplayConfigurationController( display_manager_.get(), window_tree_host_manager_.get())); - -#if defined(USE_OZONE) - display_configurator_->Init( - ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(), - !gpu_support_->IsPanelFittingDisabled()); -#elif defined(USE_X11) - display_configurator_->Init( - base::MakeUnique<display::NativeDisplayDelegateX11>(), - !gpu_support_->IsPanelFittingDisabled()); -#endif + display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(), + !gpu_support_->IsPanelFittingDisabled()); } // The DBusThreadManager must outlive this Shell. See the DCHECK in ~Shell. @@ -874,7 +862,10 @@ display_configurator_->AddObserver(projecting_observer_.get()); AddShellObserver(projecting_observer_.get()); - if (!display_initialized && chromeos::IsRunningAsSystemCompositor()) { + // TODO(sky): once simplified display management is enabled for mash + // config == Config::MUS should be config != Config::CLASSIC. + if (!display_initialized && + (config == Config::MUS || chromeos::IsRunningAsSystemCompositor())) { display_change_observer_ = base::MakeUnique<display::DisplayChangeObserver>( display_configurator_.get(), display_manager_.get()); @@ -1057,7 +1048,8 @@ // WindowTreeHostManager::InitDisplays() // since AshTouchTransformController listens on // WindowTreeHostManager::Observer::OnDisplaysInitialized(). - if (config != Config::MASH) { + // TODO(sky): needs to to work for mus too. + if (config == Config::CLASSIC) { touch_transformer_controller_.reset(new AshTouchTransformController( display_configurator_.get(), display_manager_.get())); }
diff --git a/ash/shell_init_params.h b/ash/shell_init_params.h index 7a10cd73..2b4ab73 100644 --- a/ash/shell_init_params.h +++ b/ash/shell_init_params.h
@@ -29,6 +29,8 @@ ShellPort* shell_port = nullptr; // Shell takes ownership of |primary_window_tree_host|. This is only used // by mash. + // TODO(sky): once simplified display management is enabled for mash this + // should no longer be necessary. http://crbug.com/708287. aura::WindowTreeHostMus* primary_window_tree_host = nullptr; ShellDelegate* delegate = nullptr; ui::ContextFactory* context_factory = nullptr;
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index f49a5ac..5e62df8a 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc
@@ -225,7 +225,7 @@ // static void AshTestBase::UpdateDisplay(const std::string& display_specs) { - if (Shell::GetAshConfig() != Config::CLASSIC) { + if (Shell::GetAshConfig() == Config::MASH) { ash_test_helper_->UpdateDisplayForMash(display_specs); } else { display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 28d129e..0affe9d9 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -240,7 +240,8 @@ dbus_thread_manager_initialized_ = false; } - ui::TerminateContextFactoryForTests(); + if (config_ == Config::CLASSIC) + ui::TerminateContextFactoryForTests(); ui::ShutdownInputMethodForTesting(); zero_duration_mode_.reset(); @@ -308,7 +309,7 @@ } display::Display AshTestHelper::GetSecondaryDisplay() { - if (config_ == Config::CLASSIC) + if (config_ != Config::MASH) return Shell::Get()->display_manager()->GetSecondaryDisplay(); std::vector<RootWindowController*> roots = GetRootsOrderedByDisplayId(); @@ -319,10 +320,12 @@ void AshTestHelper::CreateMashWindowManager() { CHECK(config_ != Config::CLASSIC); - window_manager_app_ = base::MakeUnique<mus::WindowManagerApplication>(); + const bool show_primary_root_on_connect = false; + window_manager_app_ = base::MakeUnique<mus::WindowManagerApplication>( + show_primary_root_on_connect); window_manager_app_->window_manager_.reset( - new mus::WindowManager(nullptr, config_)); + new mus::WindowManager(nullptr, config_, show_primary_root_on_connect)); window_manager_app_->window_manager()->shell_delegate_.reset( test_shell_delegate_); window_manager_app_->window_manager() @@ -345,8 +348,12 @@ window_manager_app_->window_manager()->window_tree_client(); window_tree_client_private_ = base::MakeUnique<aura::WindowTreeClientPrivate>(window_tree_client); - int next_x = 0; - CreateRootWindowController("800x600", &next_x); + if (config_ == Config::MUS) { + window_tree_client_private_->CallOnConnect(); + } else { + int next_x = 0; + CreateRootWindowController("800x600", &next_x); + } // Make sure the NetworkHandler didn't get turned on, see above comment as to // why the NetworkHandler should not be running.
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 462f4328..539cd2c 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -480,7 +480,7 @@ // TODO: fix. This test verifies that when a window is added the bounds are // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes // from NativeWidgetAura), which means this test now fails for aura-mus. - if (Shell::GetAshConfig() != Config::MASH) { + if (Shell::GetAshConfig() == Config::CLASSIC) { EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), window->GetBounds().ToString()); }
diff --git a/base/containers/flat_set.h b/base/containers/flat_set.h index 13f44dd..66b77af 100644 --- a/base/containers/flat_set.h +++ b/base/containers/flat_set.h
@@ -5,6 +5,8 @@ #ifndef BASE_CONTAINERS_FLAT_SET_H_ #define BASE_CONTAINERS_FLAT_SET_H_ +#include <functional> + #include "base/containers/flat_tree.h" namespace base {
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h index 2c3d506..bcfba9b 100644 --- a/base/mac/sdk_forward_declarations.h +++ b/base/mac/sdk_forward_declarations.h
@@ -247,6 +247,11 @@ action:(SEL)action; @end +@interface NSTextField (SierraPointOneSDK) ++ (instancetype)labelWithAttributedString: + (NSAttributedString*)attributedStringValue; +@end + @interface NSApplication (SierraPointOneSDK) @property BOOL automaticCustomizeTouchBarMenuItemEnabled; @end
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 7a668547..dba659e 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -414,7 +414,8 @@ ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull) { DCHECK_GT(total_probability, 0); DCHECK(!trial_name_.empty()); - DCHECK(!default_group_name_.empty()); + DCHECK(!default_group_name_.empty()) + << "Trial " << trial_name << " is missing a default group name."; } FieldTrial::~FieldTrial() {}
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc index da21d5ea..a8fbfca 100644 --- a/base/task_scheduler/task_tracker.cc +++ b/base/task_scheduler/task_tracker.cc
@@ -74,11 +74,15 @@ const char kRunFunctionName[] = "TaskSchedulerRunTask"; HistogramBase* GetTaskLatencyHistogram(const char* suffix) { - // Mimics the UMA_HISTOGRAM_TIMES macro. - return Histogram::FactoryTimeGet( - std::string("TaskScheduler.TaskLatency.") + suffix, - TimeDelta::FromMilliseconds(1), TimeDelta::FromSeconds(10), 50, - HistogramBase::kUmaTargetedHistogramFlag); + // Mimics the UMA_HISTOGRAM_TIMES macro except we don't specify bounds with + // TimeDeltas as FactoryTimeGet assumes millisecond granularity. The minimums + // and maximums were chosen to place the 1ms mark at around the 70% range + // coverage for buckets giving us good info for tasks that have a latency + // below 1ms (most of them) and enough info to assess how bad the latency is + // for tasks that exceed this threshold. + return Histogram::FactoryGet( + std::string("TaskScheduler.TaskLatencyMicroseconds.") + suffix, 1, 20000, + 50, HistogramBase::kUmaTargetedHistogramFlag); } // Upper bound for the @@ -495,7 +499,7 @@ task->traits.with_base_sync_primitives() ? 1 : 0] - ->AddTime(task_latency); + ->Add(task_latency.InMicroseconds()); } } // namespace internal
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc index e1596f7..96bda677 100644 --- a/base/task_scheduler/task_tracker_unittest.cc +++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -913,29 +913,33 @@ const char* const expected_histogram; } tests[] = { {TaskTraits().WithPriority(TaskPriority::BACKGROUND), - "TaskScheduler.TaskLatency.BackgroundTaskPriority"}, + "TaskScheduler.TaskLatencyMicroseconds.BackgroundTaskPriority"}, {TaskTraits().WithPriority(TaskPriority::BACKGROUND).MayBlock(), - "TaskScheduler.TaskLatency.BackgroundTaskPriority.MayBlock"}, + "TaskScheduler.TaskLatencyMicroseconds.BackgroundTaskPriority.MayBlock"}, {TaskTraits() .WithPriority(TaskPriority::BACKGROUND) .WithBaseSyncPrimitives(), - "TaskScheduler.TaskLatency.BackgroundTaskPriority.MayBlock"}, + "TaskScheduler.TaskLatencyMicroseconds.BackgroundTaskPriority.MayBlock"}, {TaskTraits().WithPriority(TaskPriority::USER_VISIBLE), - "TaskScheduler.TaskLatency.UserVisibleTaskPriority"}, + "TaskScheduler.TaskLatencyMicroseconds.UserVisibleTaskPriority"}, {TaskTraits().WithPriority(TaskPriority::USER_VISIBLE).MayBlock(), - "TaskScheduler.TaskLatency.UserVisibleTaskPriority.MayBlock"}, + "TaskScheduler.TaskLatencyMicroseconds.UserVisibleTaskPriority." + "MayBlock"}, {TaskTraits() .WithPriority(TaskPriority::USER_VISIBLE) .WithBaseSyncPrimitives(), - "TaskScheduler.TaskLatency.UserVisibleTaskPriority.MayBlock"}, + "TaskScheduler.TaskLatencyMicroseconds.UserVisibleTaskPriority." + "MayBlock"}, {TaskTraits().WithPriority(TaskPriority::USER_BLOCKING), - "TaskScheduler.TaskLatency.UserBlockingTaskPriority"}, + "TaskScheduler.TaskLatencyMicroseconds.UserBlockingTaskPriority"}, {TaskTraits().WithPriority(TaskPriority::USER_BLOCKING).MayBlock(), - "TaskScheduler.TaskLatency.UserBlockingTaskPriority.MayBlock"}, + "TaskScheduler.TaskLatencyMicroseconds.UserBlockingTaskPriority." + "MayBlock"}, {TaskTraits() .WithPriority(TaskPriority::USER_BLOCKING) .WithBaseSyncPrimitives(), - "TaskScheduler.TaskLatency.UserBlockingTaskPriority.MayBlock"}}; + "TaskScheduler.TaskLatencyMicroseconds.UserBlockingTaskPriority." + "MayBlock"}}; for (const auto& test : tests) { auto task =
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index c3e2a42..a41a140 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -54,31 +54,6 @@ StaticAtomicSequenceNumber g_next_guid; MemoryDumpManager* g_instance_for_testing = nullptr; -// The list of names of dump providers that are blacklisted from strict thread -// affinity check on unregistration. These providers could potentially cause -// crashes on build bots if they do not unregister on right thread. -// TODO(ssid): Fix all the dump providers to unregister if needed and clear the -// blacklist, crbug.com/643438. -const char* const kStrictThreadCheckBlacklist[] = { - "ClientDiscardableSharedMemoryManager", - "ContextProviderCommandBuffer", - "DiscardableSharedMemoryManager", - "FontCaches", - "GpuMemoryBufferVideoFramePool", - "IndexedDBBackingStore", - "Sql", - "ThreadLocalEventBuffer", - "TraceLog", - "URLRequestContext", - "VpxVideoDecoder", - "cc::SoftwareImageDecodeCache", - "cc::StagingBufferPool", - "gpu::BufferManager", - "gpu::MappedMemoryManager", - "gpu::RenderbufferManager", - "BlacklistTestDumpProvider" // for testing -}; - // Callback wrapper to hook upon the completion of RequestGlobalDump() and // inject trace markers. void OnGlobalDumpDone(GlobalMemoryDumpCallback wrapped_callback, @@ -191,9 +166,6 @@ // At this point the command line may not be initialized but we try to // enable the heap profiler to capture allocations as soon as possible. EnableHeapProfilingIfNeeded(); - - strict_thread_check_blacklist_.insert(std::begin(kStrictThreadCheckBlacklist), - std::end(kStrictThreadCheckBlacklist)); } MemoryDumpManager::~MemoryDumpManager() { @@ -398,15 +370,7 @@ // - When the provider is removed from other clients (MemoryPeakDetector). DCHECK(!(*mdp_iter)->owned_dump_provider); (*mdp_iter)->owned_dump_provider = std::move(owned_mdp); - } else if (strict_thread_check_blacklist_.count((*mdp_iter)->name) == 0 || - subtle::NoBarrier_Load(&is_enabled_)) { - // If dump provider's name is on |strict_thread_check_blacklist_|, then the - // DCHECK is fired only when tracing is enabled. Otherwise the DCHECK is - // fired even when tracing is not enabled (stricter). - // TODO(ssid): Remove this condition after removing all the dump providers - // in the blacklist and the buildbots are no longer flakily hitting the - // DCHECK, crbug.com/643438. - + } else { // If you hit this DCHECK, your dump provider has a bug. // Unregistration of a MemoryDumpProvider is safe only if: // - The MDP has specified a sequenced task runner affinity AND the
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h index 8cf8cd75..03192bf 100644 --- a/base/trace_event/memory_dump_manager.h +++ b/base/trace_event/memory_dump_manager.h
@@ -295,11 +295,6 @@ // Shared among all the PMDs to keep state scoped to the tracing session. scoped_refptr<MemoryDumpSessionState> session_state_; - // The list of names of dump providers that are blacklisted from strict thread - // affinity check on unregistration. - std::unordered_set<StringPiece, StringPieceHash> - strict_thread_check_blacklist_; - std::unique_ptr<MemoryTracingObserver> tracing_observer_; // Function provided by the embedder to handle global dump requests.
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc index 946b5b64..9d2d439 100644 --- a/base/trace_event/memory_dump_manager_unittest.cc +++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -1270,23 +1270,6 @@ DisableTracing(); } -TEST_F(MemoryDumpManagerTest, TestBlacklistedUnsafeUnregistration) { - InitializeMemoryDumpManager(false /* is_coordinator */); - MockMemoryDumpProvider mdp1; - RegisterDumpProvider(&mdp1, nullptr, kDefaultOptions, - "BlacklistTestDumpProvider"); - // Not calling UnregisterAndDeleteDumpProviderSoon() should not crash. - mdm_->UnregisterDumpProvider(&mdp1); - - Thread thread("test thread"); - thread.Start(); - RegisterDumpProvider(&mdp1, thread.task_runner(), kDefaultOptions, - "BlacklistTestDumpProvider"); - // Unregistering on wrong thread should not crash. - mdm_->UnregisterDumpProvider(&mdp1); - thread.Stop(); -} - // Tests that we can manually take a dump without enabling tracing. TEST_F(MemoryDumpManagerTest, DumpWithTracingDisabled) { InitializeMemoryDumpManager(false /* is_coordinator */);
diff --git a/base/values.cc b/base/values.cc index aa3407fd..768e3f79 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -611,7 +611,7 @@ dict_->clear(); } -void DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) { +Value* DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) { DCHECK(IsStringUTF8(path)); DCHECK(in_value); @@ -633,67 +633,94 @@ current_path = current_path.substr(delimiter_position + 1); } - current_dictionary->SetWithoutPathExpansion(current_path, - std::move(in_value)); + return current_dictionary->SetWithoutPathExpansion(current_path, + std::move(in_value)); } -void DictionaryValue::Set(StringPiece path, Value* in_value) { - Set(path, WrapUnique(in_value)); +Value* DictionaryValue::Set(StringPiece path, Value* in_value) { + return Set(path, WrapUnique(in_value)); } -void DictionaryValue::SetBoolean(StringPiece path, bool in_value) { - Set(path, new Value(in_value)); +Value* DictionaryValue::SetBoolean(StringPiece path, bool in_value) { + return Set(path, new Value(in_value)); } -void DictionaryValue::SetInteger(StringPiece path, int in_value) { - Set(path, new Value(in_value)); +Value* DictionaryValue::SetInteger(StringPiece path, int in_value) { + return Set(path, new Value(in_value)); } -void DictionaryValue::SetDouble(StringPiece path, double in_value) { - Set(path, new Value(in_value)); +Value* DictionaryValue::SetDouble(StringPiece path, double in_value) { + return Set(path, new Value(in_value)); } -void DictionaryValue::SetString(StringPiece path, StringPiece in_value) { - Set(path, new Value(in_value)); +Value* DictionaryValue::SetString(StringPiece path, StringPiece in_value) { + return Set(path, new Value(in_value)); } -void DictionaryValue::SetString(StringPiece path, const string16& in_value) { - Set(path, new Value(in_value)); +Value* DictionaryValue::SetString(StringPiece path, const string16& in_value) { + return Set(path, new Value(in_value)); } -void DictionaryValue::SetWithoutPathExpansion(StringPiece key, - std::unique_ptr<Value> in_value) { - (*dict_)[key.as_string()] = std::move(in_value); +DictionaryValue* DictionaryValue::SetDictionary( + StringPiece path, + std::unique_ptr<DictionaryValue> in_value) { + return static_cast<DictionaryValue*>(Set(path, std::move(in_value))); } -void DictionaryValue::SetWithoutPathExpansion(StringPiece key, - Value* in_value) { - SetWithoutPathExpansion(key, WrapUnique(in_value)); +ListValue* DictionaryValue::SetList(StringPiece path, + std::unique_ptr<ListValue> in_value) { + return static_cast<ListValue*>(Set(path, std::move(in_value))); } -void DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path, - bool in_value) { - SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +Value* DictionaryValue::SetWithoutPathExpansion( + StringPiece key, + std::unique_ptr<Value> in_value) { + return ((*dict_)[key.as_string()] = std::move(in_value)).get(); } -void DictionaryValue::SetIntegerWithoutPathExpansion(StringPiece path, - int in_value) { - SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +Value* DictionaryValue::SetWithoutPathExpansion(StringPiece key, + Value* in_value) { + return SetWithoutPathExpansion(key, WrapUnique(in_value)); } -void DictionaryValue::SetDoubleWithoutPathExpansion(StringPiece path, - double in_value) { - SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +Value* DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path, + bool in_value) { + return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); } -void DictionaryValue::SetStringWithoutPathExpansion(StringPiece path, - StringPiece in_value) { - SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +Value* DictionaryValue::SetIntegerWithoutPathExpansion(StringPiece path, + int in_value) { + return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); } -void DictionaryValue::SetStringWithoutPathExpansion(StringPiece path, - const string16& in_value) { - SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +Value* DictionaryValue::SetDoubleWithoutPathExpansion(StringPiece path, + double in_value) { + return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +} + +Value* DictionaryValue::SetStringWithoutPathExpansion(StringPiece path, + StringPiece in_value) { + return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +} + +Value* DictionaryValue::SetStringWithoutPathExpansion( + StringPiece path, + const string16& in_value) { + return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value)); +} + +DictionaryValue* DictionaryValue::SetDictionaryWithoutPathExpansion( + StringPiece path, + std::unique_ptr<DictionaryValue> in_value) { + return static_cast<DictionaryValue*>( + SetWithoutPathExpansion(path, std::move(in_value))); +} + +ListValue* DictionaryValue::SetListWithoutPathExpansion( + StringPiece path, + std::unique_ptr<ListValue> in_value) { + return static_cast<ListValue*>( + SetWithoutPathExpansion(path, std::move(in_value))); } bool DictionaryValue::Get(StringPiece path,
diff --git a/base/values.h b/base/values.h index 920c0a3..8b86b1e 100644 --- a/base/values.h +++ b/base/values.h
@@ -238,32 +238,41 @@ // If the key at any step of the way doesn't exist, or exists but isn't // a DictionaryValue, a new DictionaryValue will be created and attached // to the path in that location. |in_value| must be non-null. - void Set(StringPiece path, std::unique_ptr<Value> in_value); + // Returns a pointer to the inserted value. + Value* Set(StringPiece path, std::unique_ptr<Value> in_value); // Deprecated version of the above. TODO(estade): remove. - void Set(StringPiece path, Value* in_value); + Value* Set(StringPiece path, Value* in_value); // Convenience forms of Set(). These methods will replace any existing // value at that path, even if it has a different type. - void SetBoolean(StringPiece path, bool in_value); - void SetInteger(StringPiece path, int in_value); - void SetDouble(StringPiece path, double in_value); - void SetString(StringPiece path, StringPiece in_value); - void SetString(StringPiece path, const string16& in_value); + Value* SetBoolean(StringPiece path, bool in_value); + Value* SetInteger(StringPiece path, int in_value); + Value* SetDouble(StringPiece path, double in_value); + Value* SetString(StringPiece path, StringPiece in_value); + Value* SetString(StringPiece path, const string16& in_value); + DictionaryValue* SetDictionary(StringPiece path, + std::unique_ptr<DictionaryValue> in_value); + ListValue* SetList(StringPiece path, std::unique_ptr<ListValue> in_value); // Like Set(), but without special treatment of '.'. This allows e.g. URLs to // be used as paths. - void SetWithoutPathExpansion(StringPiece key, - std::unique_ptr<Value> in_value); + Value* SetWithoutPathExpansion(StringPiece key, + std::unique_ptr<Value> in_value); // Deprecated version of the above. TODO(estade): remove. - void SetWithoutPathExpansion(StringPiece key, Value* in_value); + Value* SetWithoutPathExpansion(StringPiece key, Value* in_value); // Convenience forms of SetWithoutPathExpansion(). - void SetBooleanWithoutPathExpansion(StringPiece path, bool in_value); - void SetIntegerWithoutPathExpansion(StringPiece path, int in_value); - void SetDoubleWithoutPathExpansion(StringPiece path, double in_value); - void SetStringWithoutPathExpansion(StringPiece path, StringPiece in_value); - void SetStringWithoutPathExpansion(StringPiece path, - const string16& in_value); + Value* SetBooleanWithoutPathExpansion(StringPiece path, bool in_value); + Value* SetIntegerWithoutPathExpansion(StringPiece path, int in_value); + Value* SetDoubleWithoutPathExpansion(StringPiece path, double in_value); + Value* SetStringWithoutPathExpansion(StringPiece path, StringPiece in_value); + Value* SetStringWithoutPathExpansion(StringPiece path, + const string16& in_value); + DictionaryValue* SetDictionaryWithoutPathExpansion( + StringPiece path, + std::unique_ptr<DictionaryValue> in_value); + ListValue* SetListWithoutPathExpansion(StringPiece path, + std::unique_ptr<ListValue> in_value); // Gets the Value associated with the given path starting from this object. // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
diff --git a/base/values_unittest.cc b/base/values_unittest.cc index da4d267..125c814 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc
@@ -574,6 +574,113 @@ EXPECT_TRUE(dict.empty()); } +TEST(ValuesTest, DictionarySetReturnsPointer) { + { + DictionaryValue dict; + Value* blank_ptr = dict.Set("foo.bar", base::MakeUnique<base::Value>()); + EXPECT_EQ(Value::Type::NONE, blank_ptr->type()); + } + + { + DictionaryValue dict; + Value* blank_ptr = dict.SetWithoutPathExpansion( + "foo.bar", base::MakeUnique<base::Value>()); + EXPECT_EQ(Value::Type::NONE, blank_ptr->type()); + } + + { + DictionaryValue dict; + Value* bool_ptr = dict.SetBooleanWithoutPathExpansion("foo.bar", false); + EXPECT_EQ(Value::Type::BOOLEAN, bool_ptr->type()); + EXPECT_FALSE(bool_ptr->GetBool()); + } + + { + DictionaryValue dict; + Value* int_ptr = dict.SetInteger("foo.bar", 42); + EXPECT_EQ(Value::Type::INTEGER, int_ptr->type()); + EXPECT_EQ(42, int_ptr->GetInt()); + } + + { + DictionaryValue dict; + Value* int_ptr = dict.SetIntegerWithoutPathExpansion("foo.bar", 123); + EXPECT_EQ(Value::Type::INTEGER, int_ptr->type()); + EXPECT_EQ(123, int_ptr->GetInt()); + } + + { + DictionaryValue dict; + Value* double_ptr = dict.SetDouble("foo.bar", 3.142); + EXPECT_EQ(Value::Type::DOUBLE, double_ptr->type()); + EXPECT_EQ(3.142, double_ptr->GetDouble()); + } + + { + DictionaryValue dict; + Value* double_ptr = dict.SetDoubleWithoutPathExpansion("foo.bar", 2.718); + EXPECT_EQ(Value::Type::DOUBLE, double_ptr->type()); + EXPECT_EQ(2.718, double_ptr->GetDouble()); + } + + { + DictionaryValue dict; + Value* string_ptr = dict.SetString("foo.bar", "foo"); + EXPECT_EQ(Value::Type::STRING, string_ptr->type()); + EXPECT_EQ("foo", string_ptr->GetString()); + } + + { + DictionaryValue dict; + Value* string_ptr = dict.SetStringWithoutPathExpansion("foo.bar", "bar"); + EXPECT_EQ(Value::Type::STRING, string_ptr->type()); + EXPECT_EQ("bar", string_ptr->GetString()); + } + + { + DictionaryValue dict; + Value* string16_ptr = dict.SetString("foo.bar", ASCIIToUTF16("baz")); + EXPECT_EQ(Value::Type::STRING, string16_ptr->type()); + EXPECT_EQ("baz", string16_ptr->GetString()); + } + + { + DictionaryValue dict; + Value* string16_ptr = + dict.SetStringWithoutPathExpansion("foo.bar", ASCIIToUTF16("qux")); + EXPECT_EQ(Value::Type::STRING, string16_ptr->type()); + EXPECT_EQ("qux", string16_ptr->GetString()); + } + + { + DictionaryValue dict; + DictionaryValue* dict_ptr = dict.SetDictionary( + "foo.bar", base::MakeUnique<base::DictionaryValue>()); + EXPECT_EQ(Value::Type::DICTIONARY, dict_ptr->type()); + } + + { + DictionaryValue dict; + DictionaryValue* dict_ptr = dict.SetDictionaryWithoutPathExpansion( + "foo.bar", base::MakeUnique<base::DictionaryValue>()); + EXPECT_EQ(Value::Type::DICTIONARY, dict_ptr->type()); + } + + { + DictionaryValue dict; + ListValue* list_ptr = + dict.SetList("foo.bar", base::MakeUnique<base::ListValue>()); + EXPECT_EQ(Value::Type::LIST, list_ptr->type()); + } + + { + DictionaryValue dict; + ListValue* list_ptr = dict.SetListWithoutPathExpansion( + "foo.bar", base::MakeUnique<base::ListValue>()); + EXPECT_EQ(Value::Type::LIST, list_ptr->type()); + } +} + TEST(ValuesTest, DictionaryRemoval) { std::string key = "test"; std::unique_ptr<Value> removed_item;
diff --git a/build/config/linux/gtk/gtk.gni b/build/config/linux/gtk/gtk.gni index 0521a8c..53e943e 100644 --- a/build/config/linux/gtk/gtk.gni +++ b/build/config/linux/gtk/gtk.gni
@@ -8,8 +8,5 @@ declare_args() { # Whether to compile against GTKv3 instead of GTKv2. - # TODO(thomasanderson): Currently, the 32-bit clusterfuzz schroot does not - # have libgtk-3-0 installed. set use_gtk3 = true on all architectures when - # the package is added (crbug.com/699669). - use_gtk3 = target_cpu == "x64" + use_gtk3 = true }
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index dfd1879..be55c0f 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -248,8 +248,10 @@ extra_ldflags = "" } - enable_linker_map = - defined(invoker.enable_linker_map) && invoker.enable_linker_map + # Currently disabled on LLD because of a bug (fixed upstream). + # See https://crbug.com/716209. + enable_linker_map = defined(invoker.enable_linker_map) && + invoker.enable_linker_map && !use_lld # These library switches can apply to all tools below. lib_switch = "-l"
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h index a8c586e..e7d8847 100644 --- a/cc/input/main_thread_scrolling_reason.h +++ b/cc/input/main_thread_scrolling_reason.h
@@ -44,7 +44,8 @@ kHasBorderRadius = 1 << 19, kHasClipRelatedProperty = 1 << 20, kHasBoxShadowFromNonRootLayer = 1 << 21, - kNonCompositedReasonsLast = 21, + kIsNotStackingContextAndLCDText = 1 << 22, + kNonCompositedReasonsLast = 22, // Transient scrolling reasons. These are computed for each scroll begin. kNonFastScrollableRegion = 1 << 5, @@ -59,13 +60,14 @@ // New flags should increment this number but it should never be decremented // because the values are used in UMA histograms. It should also be noted // that it excludes the kNotScrollingOnMain value. - kMainThreadScrollingReasonCount = 22, + kMainThreadScrollingReasonCount = 23, }; static const uint32_t kNonCompositedReasons = kHasOpacityAndLCDText | kHasTransformAndLCDText | kBackgroundNotOpaqueInRectAndLCDText | kHasBorderRadius | - kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer; + kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer | + kIsNotStackingContextAndLCDText; // Returns true if the given MainThreadScrollingReason can be set by the main // thread. @@ -140,6 +142,8 @@ tracedValue->AppendString("Has clip related property"); if (reasons & MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer) tracedValue->AppendString("Has box shadow from non-root layer"); + if (reasons & MainThreadScrollingReason::kIsNotStackingContextAndLCDText) + tracedValue->AppendString("Is not stacking context and LCD text"); // Transient scrolling reasons. if (reasons & MainThreadScrollingReason::kNonFastScrollableRegion)
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index f22545c..146296d 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc
@@ -50,8 +50,7 @@ Layer::PushPropertiesTo(base_layer); TRACE_EVENT0("cc", "PictureLayer::PushPropertiesTo"); PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); - // TODO(danakj): Make mask_type_ a constructor parameter for PictureLayer. - DCHECK_EQ(layer_impl->mask_type(), mask_type()); + layer_impl->SetLayerMaskType(mask_type()); DropRecordingSourceContentIfInvalid(); layer_impl->SetNearestNeighbor(picture_layer_inputs_.nearest_neighbor);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index f385bddd..0f35040 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -120,6 +120,17 @@ layer_tree_impl()->UnregisterPictureLayerImpl(this); } +void PictureLayerImpl::SetLayerMaskType(Layer::LayerMaskType mask_type) { + if (mask_type_ == mask_type) + return; + // It is expected that a layer can never change from being a mask to not being + // one and vice versa. Only changes that make mask layer single <-> multi are + // expected. + DCHECK(mask_type_ != Layer::LayerMaskType::NOT_MASK && + mask_type != Layer::LayerMaskType::NOT_MASK); + mask_type_ = mask_type; +} + const char* PictureLayerImpl::LayerTypeAsString() const { return "cc::PictureLayerImpl"; } @@ -131,10 +142,10 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) { PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); - DCHECK_EQ(layer_impl->mask_type_, mask_type_); LayerImpl::PushPropertiesTo(base_layer); + layer_impl->SetLayerMaskType(mask_type()); // Twin relationships should never change once established. DCHECK(!twin_layer_ || twin_layer_ == layer_impl); DCHECK(!twin_layer_ || layer_impl->twin_layer_ == this);
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index 0e85d8d..ba8fa4c 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -38,6 +38,7 @@ ~PictureLayerImpl() override; Layer::LayerMaskType mask_type() const { return mask_type_; } + void SetLayerMaskType(Layer::LayerMaskType type); // LayerImpl overrides. const char* LayerTypeAsString() const override; @@ -150,7 +151,7 @@ bool was_screen_space_transform_animating_; bool only_used_low_res_last_append_quads_; - const Layer::LayerMaskType mask_type_; + Layer::LayerMaskType mask_type_; bool nearest_neighbor_; bool use_transformed_rasterization_;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionMainMenuFooter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionMainMenuFooter.java index 62e8031..f77c23d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionMainMenuFooter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionMainMenuFooter.java
@@ -46,6 +46,9 @@ TextView itemSummary = (TextView) findViewById(R.id.menu_item_summary); if (DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()) { + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_MAIN_MENU_DISPLAYED_ON); + String dataSaved = Formatter.formatShortFileSize(getContext(), DataReductionProxySettings.getInstance() .getContentLengthSavedInHistorySummary()); @@ -65,6 +68,9 @@ getContext().getResources(), R.color.light_active_color); itemText.setTextColor(lightActiveColor); } else { + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_MAIN_MENU_DISPLAYED_OFF); + itemText.setText(R.string.data_reduction_title); itemSummary.setText(R.string.text_off);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionProxyUma.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionProxyUma.java index be135f5e..0e9b64c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionProxyUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionProxyUma.java
@@ -46,7 +46,13 @@ public static final int ACTION_MAIN_MENU_ON_TO_OFF = 18; public static final int ACTION_MAIN_MENU_ON_TO_ON = 19; public static final int ACTION_STATS_RESET = 20; - public static final int ACTION_INDEX_BOUNDARY = 21; + public static final int ACTION_MAIN_MENU_DISPLAYED_ON = 21; + public static final int ACTION_MAIN_MENU_DISPLAYED_OFF = 22; + public static final int ACTION_SITE_BREAKDOWN_DISPLAYED = 23; + public static final int ACTION_SITE_BREAKDOWN_SORTED_BY_DATA_SAVED = 24; + public static final int ACTION_SITE_BREAKDOWN_SORTED_BY_DATA_USED = 25; + public static final int ACTION_SITE_BREAKDOWN_EXPANDED = 26; + public static final int ACTION_INDEX_BOUNDARY = 27; // Represent the possible Lo-Fi context menu user actions. This must remain in sync with // Previews.ContextMenuAction.LoFi in tools/metrics/histograms/histograms.xml.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionSiteBreakdownView.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionSiteBreakdownView.java index 1a72748..8450c91e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionSiteBreakdownView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionSiteBreakdownView.java
@@ -59,6 +59,8 @@ mDataUsedTitle.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_SITE_BREAKDOWN_SORTED_BY_DATA_USED); setTextViewUnsortedAttributes(mDataSavedTitle); setTextViewSortedAttributes(mDataUsedTitle); Collections.sort(mDataUseItems, new DataUsedComparator()); @@ -69,6 +71,8 @@ mDataSavedTitle.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_SITE_BREAKDOWN_SORTED_BY_DATA_SAVED); setTextViewUnsortedAttributes(mDataUsedTitle); setTextViewSortedAttributes(mDataSavedTitle); Collections.sort(mDataUseItems, new DataSavedComparator()); @@ -86,7 +90,14 @@ setTextViewUnsortedAttributes(mDataUsedTitle); setTextViewSortedAttributes(mDataSavedTitle); Collections.sort(items, new DataSavedComparator()); - updateSiteBreakdown(); + if (mDataUseItems.size() == 0) { + setVisibility(GONE); + } else { + setVisibility(VISIBLE); + updateSiteBreakdown(); + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_SITE_BREAKDOWN_DISPLAYED); + } } private void setTextViewSortedAttributes(TextView textView) { @@ -153,12 +164,6 @@ * Update the site breakdown to display the data use items. */ private void updateSiteBreakdown() { - if (mDataUseItems.size() == 0) { - setVisibility(GONE); - return; - } - - setVisibility(VISIBLE); // Remove all old rows except the header. mTableLayout.removeViews(1, mTableLayout.getChildCount() - 1); @@ -211,6 +216,8 @@ row.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + DataReductionProxyUma.dataReductionProxyUIAction( + DataReductionProxyUma.ACTION_SITE_BREAKDOWN_EXPANDED); mNumDataUseItemsToDisplay += NUM_DATA_USE_ITEMS_TO_ADD; updateSiteBreakdown(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java index 52fb8ee..7ec917a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
@@ -154,7 +154,7 @@ mDataReductionBreakdownView = (DataReductionSiteBreakdownView) view.findViewById(R.id.breakdown); forceLayoutGravityOfGraphLabels(); - updateReductionStatistics(); + if (mOriginalNetworkStatsHistory == null) updateReductionStatistics(); setDetailText(); mChartDataUsageView = (ChartDataUsageView) view.findViewById(R.id.chart);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 69cf741..673e467 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -1960,6 +1960,9 @@ desc="Customization label for the new tab button in the touch bar."> New Tab </message> + <message name="IDS_TOUCH_BAR_EXIT_FULLSCREEN" desc="Text for the exit fullscreen button in the touch bar."> + Exit Full Screen + </message> </if> <!-- Remove in-progress downloads confirmation dialog -->
diff --git a/chrome/app/mash/embedded_services.cc b/chrome/app/mash/embedded_services.cc index 65ef4da..88f5152a 100644 --- a/chrome/app/mash/embedded_services.cc +++ b/chrome/app/mash/embedded_services.cc
@@ -31,8 +31,11 @@ std::unique_ptr<service_manager::Service> CreateEmbeddedMashService( const std::string& service_name) { #if defined(OS_CHROMEOS) - if (service_name == ash::mojom::kServiceName) - return base::MakeUnique<ash::mus::WindowManagerApplication>(); + if (service_name == ash::mojom::kServiceName) { + const bool show_primary_host_on_connect = true; + return base::WrapUnique( + new ash::mus::WindowManagerApplication(show_primary_host_on_connect)); + } if (service_name == "accessibility_autoclick") return base::MakeUnique<ash::autoclick::AutoclickApplication>(); if (service_name == "touch_hud")
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index d9a048e..14c1ced 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2506,6 +2506,10 @@ flag_descriptions::kVideoFullscreenOrientationLockName, flag_descriptions::kVideoFullscreenOrientationLockDescription, kOsAndroid, FEATURE_VALUE_TYPE(media::kVideoFullscreenOrientationLock)}, + {"video-rotate-to-fullscreen", + flag_descriptions::kVideoRotateToFullscreenName, + flag_descriptions::kVideoRotateToFullscreenDescription, kOsAndroid, + FEATURE_VALUE_TYPE(media::kVideoRotateToFullscreen)}, #endif {"enable-nostate-prefetch", flag_descriptions::kNostatePrefetch, flag_descriptions::kNostatePrefetchDescription, kOsAll, @@ -2622,8 +2626,8 @@ {"enable-zero-suggest-redirect-to-chrome", flag_descriptions::kEnableZeroSuggestRedirectToChromeName, - flag_descriptions::kEnableZeroSuggestRedirectToChromeDescription, - kOsDesktop, FEATURE_VALUE_TYPE(omnibox::kZeroSuggestRedirectToChrome)}, + flag_descriptions::kEnableZeroSuggestRedirectToChromeDescription, kOsAll, + FEATURE_VALUE_TYPE(omnibox::kZeroSuggestRedirectToChrome)}, {"new-omnibox-answer-types", flag_descriptions::kNewOmniboxAnswerTypesName, flag_descriptions::kNewOmniboxAnswerTypesDescription, kOsAll, FEATURE_VALUE_TYPE(omnibox::kNewOmniboxAnswerTypes)},
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc index 4758d2f..02ef92b 100644 --- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc +++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -492,7 +492,8 @@ adapter = new DownloadUIAdapter( offline_page_model, request_coordinator, base::MakeUnique<DownloadUIAdapterDelegate>(offline_page_model)); - DownloadUIAdapter::AttachToOfflinePageModel(adapter, offline_page_model); + DownloadUIAdapter::AttachToOfflinePageModel(base::WrapUnique(adapter), + offline_page_model); } return reinterpret_cast<jlong>(
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc index 6f1dbe7..b93155a 100644 --- a/chrome/browser/android/offline_pages/offline_page_bridge.cc +++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -16,6 +16,7 @@ #include "base/android/jni_string.h" #include "base/bind.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" #include "chrome/browser/android/offline_pages/offline_page_utils.h" @@ -242,7 +243,8 @@ offline_page_model->GetUserData(kOfflinePageBridgeKey)); if (!bridge) { bridge = new OfflinePageBridge(env, profile, offline_page_model); - offline_page_model->SetUserData(kOfflinePageBridgeKey, bridge); + offline_page_model->SetUserData(kOfflinePageBridgeKey, + base::WrapUnique(bridge)); } return ScopedJavaLocalRef<jobject>(bridge->java_ref());
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job.cc b/chrome/browser/android/offline_pages/offline_page_request_job.cc index 570e255..9f849a3d 100644 --- a/chrome/browser/android/offline_pages/offline_page_request_job.cc +++ b/chrome/browser/android/offline_pages/offline_page_request_job.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/files/file_path.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/threading/sequenced_worker_pool.h" @@ -544,7 +545,8 @@ if (info->use_default()) return nullptr; } else { - request->SetUserData(&kUserDataKey, new OfflinePageRequestInfo()); + request->SetUserData(&kUserDataKey, + base::MakeUnique<OfflinePageRequestInfo>()); } return new OfflinePageRequestJob(request, network_delegate, previews_decider);
diff --git a/chrome/browser/android/offline_pages/offline_page_utils_unittest.cc b/chrome/browser/android/offline_pages/offline_page_utils_unittest.cc index 7c4eed2..1fda0161 100644 --- a/chrome/browser/android/offline_pages/offline_page_utils_unittest.cc +++ b/chrome/browser/android/offline_pages/offline_page_utils_unittest.cc
@@ -12,6 +12,7 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string16.h" #include "base/test/scoped_feature_list.h" @@ -133,8 +134,8 @@ &profile_, BuildTestOfflinePageModel); RunUntilIdle(); - NetworkQualityProviderStub::SetUserData(&profile_, - new NetworkQualityProviderStub()); + NetworkQualityProviderStub::SetUserData( + &profile_, base::MakeUnique<NetworkQualityProviderStub>()); RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse( &profile_, BuildTestRequestCoordinator); RunUntilIdle();
diff --git a/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.cc b/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.cc index 39f7193..327c9c3 100644 --- a/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.cc +++ b/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.cc
@@ -23,7 +23,7 @@ const SkColor kForegroundColor = 0xFF444444; constexpr float kBorderFactor = 0.1; constexpr float kIconSizeFactor = 0.7; -constexpr float kFontSizeFactor = 0.45; +constexpr float kFontSizeFactor = 0.40; constexpr float kTextHeightFactor = 1.0 - 2 * kBorderFactor; constexpr float kTextWidthFactor = 4.0 - 3 * kBorderFactor - kIconSizeFactor;
diff --git a/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.cc b/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.cc index 6c80c63..0557c2c 100644 --- a/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.cc +++ b/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.cc
@@ -22,9 +22,8 @@ const SkColor kBackgroundColor = 0xCC1A1A1A; const SkColor kForegroundColor = SK_ColorWHITE; constexpr float kBorderFactor = 0.045; -constexpr float kIconSizeFactor = 0.25; -constexpr float kFontSizeFactor = 0.045; -constexpr float kTextWidthFactor = 1.0 - 3 * kBorderFactor - kIconSizeFactor; +constexpr float kFontSizeFactor = 0.048; +constexpr float kTextWidthFactor = 1.0 - 3 * kBorderFactor; } // namespace @@ -47,9 +46,7 @@ int text_height = 0; // Will be increased during text measurement. gfx::Canvas::SizeStringInt(text, fonts, &text_width, &text_height, 0, text_flags); - // Making sure that the icon fits in the box. - text_height = std::max( - text_height, static_cast<int>(ceil(size_.width() * kIconSizeFactor))); + // Making sure the drawing fits within the texture. text_height = std::min( text_height, static_cast<int>((1.0 - 2 * kBorderFactor) * size_.width())); @@ -59,19 +56,8 @@ size_.height() * kBorderFactor, flags); canvas->Save(); - canvas->Translate( - gfx::Vector2d(IsRTL() ? 2 * kBorderFactor * size_.width() + text_width - : size_.width() * kBorderFactor, - (size_.height() - kIconSizeFactor * size_.width()) / 2.0)); - PaintVectorIcon(canvas, ui::kInfoOutlineIcon, size_.width() * kIconSizeFactor, - kForegroundColor); - canvas->Restore(); - - canvas->Save(); - canvas->Translate(gfx::Vector2d( - IsRTL() ? kBorderFactor * size_.width() - : size_.width() * (2 * kBorderFactor + kIconSizeFactor), - size_.width() * kBorderFactor)); + canvas->Translate(gfx::Vector2d(size_.width() * kBorderFactor, + size_.width() * kBorderFactor)); canvas->DrawStringRectWithFlags( text, fonts, kForegroundColor, gfx::Rect(kTextWidthFactor * size_.width(), text_height), text_flags);
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index 4cbeae4..49c4515 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -19,10 +19,10 @@ static constexpr int kWarningTimeoutSeconds = 30; static constexpr float kWarningDistance = 0.7; static constexpr float kWarningAngleRadians = 16.3 * M_PI / 180.0; -static constexpr float kPermanentWarningHeight = 0.226; -static constexpr float kPermanentWarningWidth = 0.078; -static constexpr float kTransientWarningHeight = 0.512; -static constexpr float kTransientWarningWidth = 0.160; +static constexpr float kPermanentWarningHeight = 0.070f; +static constexpr float kPermanentWarningWidth = 0.224f; +static constexpr float kTransientWarningHeight = 0.160; +static constexpr float kTransientWarningWidth = 0.512; static constexpr float kContentWidth = 2.4; static constexpr float kContentHeight = 1.6;
diff --git a/chrome/browser/android/vr_shell/vr_controller_model.cc b/chrome/browser/android/vr_shell/vr_controller_model.cc index a0a60d3..4321905 100644 --- a/chrome/browser/android/vr_shell/vr_controller_model.cc +++ b/chrome/browser/android/vr_shell/vr_controller_model.cc
@@ -10,6 +10,9 @@ #include "base/path_service.h" #include "chrome/browser/android/vr_shell/gltf_parser.h" #include "components/component_updater/component_updater_paths.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/codec/png_codec.h" namespace vr_shell { @@ -24,20 +27,40 @@ constexpr char kPosition[] = "POSITION"; constexpr char kTexCoord[] = "TEXCOORD_0"; -} // namespace +// TODO(acondor): Remove these hardcoded paths once VrShell resources +// are delivered through component updater. +constexpr char const kComponentName[] = "VrShell"; +constexpr char const kDefaultVersion[] = "0"; -constexpr char const VrControllerModel::kComponentName[]; -constexpr char const VrControllerModel::kDefaultVersion[]; -constexpr char const VrControllerModel::kModelsDirectory[]; -constexpr char const VrControllerModel::kModelFilename[]; -constexpr char const VrControllerModel::kTexturesDirectory[]; -constexpr char const* VrControllerModel::kTextureFilenames[]; +constexpr char const kModelsDirectory[] = "models"; +constexpr char const kModelFilename[] = "controller.gltf"; +constexpr char const kTexturesDirectory[] = "tex"; +constexpr char const kBaseTextureFilename[] = "ddcontroller_idle.png"; +constexpr char const* kTexturePatchesFilenames[] = { + "", "ddcontroller_touchpad.png", "ddcontroller_app.png", + "ddcontroller_system.png", +}; +const gfx::Point kPatchesLocations[] = {{}, {5, 5}, {47, 165}, {47, 234}}; + +sk_sp<SkImage> LoadPng(const base::FilePath& path) { + std::string data; + SkBitmap bitmap; + if (!base::ReadFileToString(path, &data) || + !gfx::PNGCodec::Decode( + reinterpret_cast<const unsigned char*>(data.data()), data.size(), + &bitmap) || + bitmap.colorType() != kRGBA_8888_SkColorType) { + return nullptr; + } + return SkImage::MakeFromBitmap(bitmap); +} + +} // namespace VrControllerModel::VrControllerModel( std::unique_ptr<gltf::Asset> gltf_asset, std::vector<std::unique_ptr<gltf::Buffer>> buffers) : gltf_asset_(std::move(gltf_asset)), - texture_bitmaps_(State::STATE_COUNT), buffers_(std::move(buffers)) {} VrControllerModel::~VrControllerModel() = default; @@ -92,15 +115,27 @@ return Accessor(kTexCoord); } -void VrControllerModel::SetTexture(int state, - std::unique_ptr<SkBitmap> bitmap) { - DCHECK(state >= 0 && state < STATE_COUNT); - texture_bitmaps_[state] = std::move(bitmap); +void VrControllerModel::SetBaseTexture(sk_sp<SkImage> image) { + base_texture_ = image; } -const SkBitmap* VrControllerModel::GetTexture(int state) const { +void VrControllerModel::SetTexturePatch(int state, sk_sp<SkImage> image) { DCHECK(state >= 0 && state < STATE_COUNT); - return texture_bitmaps_[state].get(); + patches_[state] = image; +} + +sk_sp<SkImage> VrControllerModel::GetTexture(int state) const { + if (!patches_[state]) + return base_texture_; + sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( + base_texture_->width(), base_texture_->height()); + SkCanvas* canvas = surface->getCanvas(); + canvas->drawImage(base_texture_, 0, 0); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawImage(patches_[state], kPatchesLocations[state].x(), + kPatchesLocations[state].y(), &paint); + return sk_sp<SkImage>(surface->makeImageSnapshot()); } const char* VrControllerModel::Buffer() const { @@ -121,10 +156,10 @@ std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() { base::FilePath models_path; PathService::Get(component_updater::DIR_COMPONENT_USER, &models_path); - models_path = models_path.Append(VrControllerModel::kComponentName) - .Append(VrControllerModel::kDefaultVersion) - .Append(VrControllerModel::kModelsDirectory); - auto model_path = models_path.Append(VrControllerModel::kModelFilename); + models_path = models_path.Append(kComponentName) + .Append(kDefaultVersion) + .Append(kModelsDirectory); + auto model_path = models_path.Append(kModelFilename); // No further action if model file is not present if (!base::PathExists(model_path)) { @@ -143,23 +178,25 @@ auto controller_model = base::MakeUnique<VrControllerModel>(std::move(asset), std::move(buffers)); - auto textures_path = - models_path.Append(VrControllerModel::kTexturesDirectory); + auto textures_path = models_path.Append(kTexturesDirectory); + + auto base_texture = LoadPng(textures_path.Append(kBaseTextureFilename)); + if (!base_texture) { + LOG(ERROR) << "Failed to read controller base texture"; + return nullptr; + } + controller_model->SetBaseTexture(std::move(base_texture)); for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) { - auto texture_path = - textures_path.Append(VrControllerModel::kTextureFilenames[i]); - std::string data; - auto bitmap = base::MakeUnique<SkBitmap>(); - if (!base::ReadFileToString(texture_path, &data) || - !gfx::PNGCodec::Decode( - reinterpret_cast<const unsigned char*>(data.data()), data.size(), - bitmap.get()) || - bitmap->colorType() != kRGBA_8888_SkColorType) { - LOG(ERROR) << "Failed to read controller texture"; - return nullptr; + if (!kTexturePatchesFilenames[i][0]) + continue; + auto patch_image = + LoadPng(textures_path.Append(kTexturePatchesFilenames[i])); + if (!patch_image) { + LOG(ERROR) << "Failed to read controller texture patch"; + continue; } - controller_model->SetTexture(i, std::move(bitmap)); + controller_model->SetTexturePatch(i, patch_image); } return controller_model;
diff --git a/chrome/browser/android/vr_shell/vr_controller_model.h b/chrome/browser/android/vr_shell/vr_controller_model.h index eb2bc88a..b679ea4d 100644 --- a/chrome/browser/android/vr_shell/vr_controller_model.h +++ b/chrome/browser/android/vr_shell/vr_controller_model.h
@@ -8,7 +8,8 @@ #include <memory> #include "chrome/browser/android/vr_shell/gltf_asset.h" -#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkImage.h" +#include "ui/gfx/geometry/point.h" #include "ui/gl/gl_bindings.h" namespace vr_shell { @@ -24,19 +25,6 @@ STATE_COUNT, }; - // TODO(acondor): Remove these hardcoded paths once VrShell resources - // are delivered through component updater. - static constexpr char const kComponentName[] = "VrShell"; - static constexpr char const kDefaultVersion[] = "0"; - - static constexpr char const kModelsDirectory[] = "models"; - static constexpr char const kModelFilename[] = "controller.gltf"; - static constexpr char const kTexturesDirectory[] = "tex"; - static constexpr char const* kTextureFilenames[] = { - "ddcontroller_idle.png", "ddcontroller_touchpad.png", - "ddcontroller_app.png", "ddcontroller_system.png", - }; - explicit VrControllerModel( std::unique_ptr<gltf::Asset> gltf_asset, std::vector<std::unique_ptr<gltf::Buffer>> buffers); @@ -50,14 +38,16 @@ const gltf::Accessor* IndicesAccessor() const; const gltf::Accessor* PositionAccessor() const; const gltf::Accessor* TextureCoordinateAccessor() const; - void SetTexture(int state, std::unique_ptr<SkBitmap> bitmap); - const SkBitmap* GetTexture(int state) const; + void SetBaseTexture(sk_sp<SkImage> image); + void SetTexturePatch(int state, sk_sp<SkImage> image); + sk_sp<SkImage> GetTexture(int state) const; static std::unique_ptr<VrControllerModel> LoadFromComponent(); private: std::unique_ptr<gltf::Asset> gltf_asset_; - std::vector<std::unique_ptr<SkBitmap>> texture_bitmaps_; + sk_sp<SkImage> base_texture_; + sk_sp<SkImage> patches_[STATE_COUNT]; std::vector<std::unique_ptr<gltf::Buffer>> buffers_; const char* Buffer() const;
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc index b037a0b0..e87c903 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -608,14 +608,19 @@ glGenTextures(VrControllerModel::STATE_COUNT, texture_handles_.data()); for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) { + sk_sp<SkImage> texture = model->GetTexture(i); + SkPixmap pixmap; + if (!texture->peekPixels(&pixmap)) { + LOG(ERROR) << "Failed to read controller texture pixels"; + continue; + } glBindTexture(GL_TEXTURE_2D, texture_handles_[i]); - const SkBitmap* bitmap = model->GetTexture(i); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->width(), bitmap->height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixmap.width(), pixmap.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixmap.addr()); } const gltf::Accessor* accessor = model->PositionAccessor();
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 09a6feb4..40753bf 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1517,12 +1517,19 @@ "login/enrollment/enterprise_enrollment_helper_mock.h", "login/enrollment/mock_enrollment_screen.cc", "login/enrollment/mock_enrollment_screen.h", + "login/mock_network_state_helper.cc", + "login/mock_network_state_helper.h", "login/screens/mock_base_screen_delegate.cc", "login/screens/mock_base_screen_delegate.h", + "login/screens/mock_model_view_channel.cc", + "login/screens/mock_model_view_channel.h", + "login/screens/mock_network_screen.cc", + "login/screens/mock_network_screen.h", ] deps = [ "//components/policy/proto", + "//skia", "//testing/gmock", ] } @@ -1667,6 +1674,7 @@ "login/quick_unlock/pin_storage_unittest.cc", "login/quick_unlock/quick_unlock_storage_unittest.cc", "login/saml/saml_offline_signin_limiter_unittest.cc", + "login/screens/network_screen_unittest.cc", "login/signin/merge_session_load_page_unittest.cc", "login/supervised/supervised_user_authentication_unittest.cc", "login/users/affiliation_unittest.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 87eafaca..a9cf2aea 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -254,7 +254,9 @@ } service_providers.push_back(base::MakeUnique<LivenessServiceProvider>()); service_providers.push_back(base::MakeUnique<ScreenLockServiceProvider>()); - if (GetAshConfig() == ash::Config::CLASSIC) { + // TODO(sky): once mash supports simplified display mode we should always + // use ChromeConsoleServiceProviderDelegate. + if (GetAshConfig() != ash::Config::MASH) { service_providers.push_back(base::MakeUnique<ConsoleServiceProvider>( base::MakeUnique<ChromeConsoleServiceProviderDelegate>())); } else {
diff --git a/chrome/browser/chromeos/login/mock_network_state_helper.cc b/chrome/browser/chromeos/login/mock_network_state_helper.cc new file mode 100644 index 0000000..0dd622d --- /dev/null +++ b/chrome/browser/chromeos/login/mock_network_state_helper.cc
@@ -0,0 +1,14 @@ +// 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 "chrome/browser/chromeos/login/mock_network_state_helper.h" + +namespace chromeos { +namespace login { + +MockNetworkStateHelper::MockNetworkStateHelper() {} +MockNetworkStateHelper::~MockNetworkStateHelper() {} + +} // namespace login +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/mock_network_state_helper.h b/chrome/browser/chromeos/login/mock_network_state_helper.h new file mode 100644 index 0000000..09a534f0b --- /dev/null +++ b/chrome/browser/chromeos/login/mock_network_state_helper.h
@@ -0,0 +1,28 @@ +// 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_LOGIN_MOCK_NETWORK_STATE_HELPER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_NETWORK_STATE_HELPER_H_ + +#include "chrome/browser/chromeos/login/helper.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +namespace login { + +class MockNetworkStateHelper : public NetworkStateHelper { + public: + MockNetworkStateHelper(); + ~MockNetworkStateHelper() override; + MOCK_CONST_METHOD0(GetCurrentNetworkName, base::string16(void)); + MOCK_CONST_METHOD0(IsConnected, bool(void)); + MOCK_CONST_METHOD0(IsConnecting, bool(void)); +}; + +} // namespace login + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_NETWORK_STATE_HELPER_H_
diff --git a/chrome/browser/chromeos/login/screens/mock_model_view_channel.cc b/chrome/browser/chromeos/login/screens/mock_model_view_channel.cc new file mode 100644 index 0000000..994beec8 --- /dev/null +++ b/chrome/browser/chromeos/login/screens/mock_model_view_channel.cc
@@ -0,0 +1,12 @@ +// 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 "chrome/browser/chromeos/login/screens/mock_model_view_channel.h" + +namespace chromeos { + +MockModelViewChannel::MockModelViewChannel() {} +MockModelViewChannel::~MockModelViewChannel() {} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_model_view_channel.h b/chrome/browser/chromeos/login/screens/mock_model_view_channel.h new file mode 100644 index 0000000..e6346ed --- /dev/null +++ b/chrome/browser/chromeos/login/screens/mock_model_view_channel.h
@@ -0,0 +1,23 @@ +// 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_LOGIN_SCREENS_MOCK_MODEL_VIEW_CHANNEL_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_MODEL_VIEW_CHANNEL_H_ + +#include "base/values.h" +#include "chrome/browser/chromeos/login/screens/model_view_channel.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +class MockModelViewChannel : public ModelViewChannel { + public: + MockModelViewChannel(); + ~MockModelViewChannel() override; + MOCK_METHOD1(CommitContextChanges, void(const base::DictionaryValue& diff)); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_MODEL_VIEW_CHANNEL_H_
diff --git a/chrome/browser/chromeos/login/screens/network_screen.cc b/chrome/browser/chromeos/login/screens/network_screen.cc index fd9d69f..cbde4e005 100644 --- a/chrome/browser/chromeos/login/screens/network_screen.cc +++ b/chrome/browser/chromeos/login/screens/network_screen.cc
@@ -363,7 +363,12 @@ if (is_connected && continue_attempts_ == 0 && policy::DeviceCloudPolicyManagerChromeOS::GetZeroTouchEnrollmentMode() == policy::ZeroTouchEnrollmentMode::HANDS_OFF) { - OnContinueButtonPressed(); + // Call OnContinueButtonPressed after 3 minutes. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::Bind(&NetworkScreen::OnContinueButtonPressed, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMinutes(3)); } }
diff --git a/chrome/browser/chromeos/login/screens/network_screen.h b/chrome/browser/chromeos/login/screens/network_screen.h index 5fe898d5..0b61db13d 100644 --- a/chrome/browser/chromeos/login/screens/network_screen.h +++ b/chrome/browser/chromeos/login/screens/network_screen.h
@@ -95,10 +95,11 @@ private: friend class NetworkScreenTest; + friend class NetworkScreenUnitTest; FRIEND_TEST_ALL_PREFIXES(NetworkScreenTest, Timeout); FRIEND_TEST_ALL_PREFIXES(NetworkScreenTest, CanConnect); - FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, RequiresNoInput); - FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, ContinueClickedOnlyOnce); + FRIEND_TEST_ALL_PREFIXES(NetworkScreenUnitTest, ContinuesAutomatically); + FRIEND_TEST_ALL_PREFIXES(NetworkScreenUnitTest, ContinuesOnlyOnce); // BaseScreen implementation: void Show() override;
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc index 3337dee..b89fca99 100644 --- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -8,9 +8,9 @@ #include "base/command_line.h" #include "base/macros.h" -#include "base/strings/utf_string_conversions.h" #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h" #include "chrome/browser/chromeos/login/helper.h" +#include "chrome/browser/chromeos/login/mock_network_state_helper.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" @@ -41,17 +41,6 @@ void ButtonPressed(views::Button* sender, const ui::Event& event) override {} }; -namespace login { - -class MockNetworkStateHelper : public NetworkStateHelper { - public: - MOCK_CONST_METHOD0(GetCurrentNetworkName, base::string16(void)); - MOCK_CONST_METHOD0(IsConnected, bool(void)); - MOCK_CONST_METHOD0(IsConnecting, bool(void)); -}; - -} // namespace login - class NetworkScreenTest : public WizardInProcessBrowserTest { public: NetworkScreenTest() @@ -157,124 +146,4 @@ // view_->ClearErrors(); } -class HandsOffNetworkScreenTest : public NetworkScreenTest { - public: - HandsOffNetworkScreenTest() {} - - protected: - void SetUpOnMainThread() override { - NetworkScreenTest::SetUpOnMainThread(); - - // Set up fake networks. - DBusThreadManager::Get() - ->GetShillManagerClient() - ->GetTestInterface() - ->SetupDefaultEnvironment(); - } - - private: - // Overridden from InProcessBrowserTest: - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII( - switches::kEnterpriseEnableZeroTouchEnrollment, "hands-off"); - } - - DISALLOW_COPY_AND_ASSIGN(HandsOffNetworkScreenTest); -}; - -#if defined(OS_CHROMEOS) -// Flaky on ChromeOS. See https://crbug.com/674782. -#define MAYBE_RequiresNoInput DISABLED_RequiresNoInput -#else -#define MAYBE_RequiresNoInput RequiresNoInput -#endif -IN_PROC_BROWSER_TEST_F(HandsOffNetworkScreenTest, MAYBE_RequiresNoInput) { - WizardController* wizard_controller = WizardController::default_controller(); - - // Allow the WizardController to advance throught the enrollment flow. - network_screen_->base_screen_delegate_ = wizard_controller; - - // Simulate a network connection. - EXPECT_CALL(*mock_network_state_helper_, IsConnected()) - .Times(AnyNumber()) - .WillRepeatedly((Return(true))); - network_screen_->UpdateStatus(); - - // Check if NetworkScreen::OnContinueButtonPressed() is called - // Note that checking network_screen_->continue_pressed_ is not - // sufficient since there are cases where OnContinueButtonPressed() - // is called but where this variable is not set to true. - ASSERT_TRUE((!network_screen_->is_network_subscribed_) && - network_screen_->network_state_helper_->IsConnected()); - - // Check that we reach the enrollment screen. - OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait(); - - // Check that attestation-based enrollment finishes - // with either success or error. - bool done = false; - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - LoginDisplayHost::default_host()->GetOobeUI()->web_ui()->GetWebContents(), - "var count = 0;" - "function isVisible(el) {" - " return window.getComputedStyle(document.getElementById(el)).display" - " !== 'none';" - "}" - "function SendReplyIfEnrollmentDone() {" - " if (isVisible('oauth-enroll-step-abe-success') ||" - " isVisible('oauth-enroll-step-error')) {" - " domAutomationController.send(true);" - " } else if (count > 10) {" - " domAutomationController.send(false);" - " } else {" - " count++;" - " setTimeout(SendReplyIfEnrollmentDone, 1000);" - " }" - "}" - "SendReplyIfEnrollmentDone();", - &done)); - - // Reset the enrollment helper so there is no side effect with other tests. - static_cast<EnrollmentScreen*>(wizard_controller->current_screen()) - ->enrollment_helper_.reset(); -} - -IN_PROC_BROWSER_TEST_F(HandsOffNetworkScreenTest, ContinueClickedOnlyOnce) { - WizardController* wizard_controller = WizardController::default_controller(); - - // Allow the WizardController to advance through the enrollment flow. - network_screen_->base_screen_delegate_ = wizard_controller; - - // Check that OnContinueButtonPressed has not been called yet. - ASSERT_EQ(0, network_screen_->continue_attempts_); - - // Connect to network "net0". - EXPECT_CALL(*mock_network_state_helper_, GetCurrentNetworkName()) - .Times(AnyNumber()) - .WillRepeatedly(Return(base::ASCIIToUTF16("net0"))); - EXPECT_CALL(*mock_network_state_helper_, IsConnected()) - .Times(AnyNumber()) - .WillRepeatedly(Return(true)); - - // Stop waiting for net0. - network_screen_->StopWaitingForConnection(base::ASCIIToUTF16("net0")); - - // Check that OnContinueButtonPressed has been called exactly once. - ASSERT_EQ(1, network_screen_->continue_attempts_); - - // Stop waiting for another network, net1. - network_screen_->StopWaitingForConnection(base::ASCIIToUTF16("net1")); - - // Check that OnContinueButtonPressed stil has been called exactly once - ASSERT_EQ(1, network_screen_->continue_attempts_); - - // Wait for the enrollment screen. - OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT) - .WaitNoAssertCurrentScreen(); - - // Reset the enrollment helper so there is no side effect with other tests. - static_cast<EnrollmentScreen*>(wizard_controller->current_screen()) - ->enrollment_helper_.reset(); -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/network_screen_unittest.cc b/chrome/browser/chromeos/login/screens/network_screen_unittest.cc new file mode 100644 index 0000000..6f55f3f --- /dev/null +++ b/chrome/browser/chromeos/login/screens/network_screen_unittest.cc
@@ -0,0 +1,160 @@ +// 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 "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" +#include "chrome/browser/chromeos/input_method/input_method_configuration.h" +#include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h" +#include "chrome/browser/chromeos/login/mock_network_state_helper.h" +#include "chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h" +#include "chrome/browser/chromeos/login/screens/mock_model_view_channel.h" +#include "chrome/browser/chromeos/login/screens/mock_network_screen.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/system/fake_statistics_provider.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/ime/chromeos/mock_component_extension_ime_manager.h" + +using testing::_; +using testing::AnyNumber; +using testing::Return; + +namespace chromeos { + +class NetworkScreenUnitTest : public testing::Test { + public: + NetworkScreenUnitTest() {} + + base::ScopedMockTimeMessageLoopTaskRunner* GetTestMessageLoopTaskRunner() { + return &runner_; + } + + void FastForwardTime(base::TimeDelta time) { + runner_.task_runner()->FastForwardBy(time); + } + + // testing::Test: + void SetUp() override { + // Initialize the thread manager. + DBusThreadManager::Initialize(); + + // Configure the browser to use Hands-Off Enrollment. + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnterpriseEnableZeroTouchEnrollment, "hands-off"); + + // Replace the regular InputMethodManager with a mock. + input_method::MockInputMethodManagerImpl* mock_input_manager = + new input_method::MockInputMethodManagerImpl(); + mock_input_manager->SetComponentExtensionIMEManager( + std::unique_ptr<MockComponentExtensionIMEManager>( + new MockComponentExtensionIMEManager())); + input_method::InitializeForTesting(mock_input_manager); + + // Create the NetworkScreen we will use for testing. + network_screen_.reset( + new NetworkScreen(&mock_base_screen_delegate_, nullptr, &mock_view_)); + network_screen_->set_model_view_channel(&mock_channel_); + mock_network_state_helper_ = new login::MockNetworkStateHelper(); + network_screen_->SetNetworkStateHelperForTest(mock_network_state_helper_); + } + + void TearDown() override { + TestingBrowserProcess::GetGlobal()->SetShuttingDown(true); + network_screen_.reset(); + input_method::Shutdown(); + DBusThreadManager::Shutdown(); + } + + protected: + // A pointer to the NetworkScreen. + std::unique_ptr<NetworkScreen> network_screen_; + + // Accessory objects needed by NetworkScreen. + MockBaseScreenDelegate mock_base_screen_delegate_; + login::MockNetworkStateHelper* mock_network_state_helper_ = nullptr; + + private: + // Test versions of core browser infrastructure. + content::TestBrowserThreadBundle threads_; + base::ScopedMockTimeMessageLoopTaskRunner runner_; + + // More accessory objects needed by NetworkScreen. + MockNetworkView mock_view_; + MockModelViewChannel mock_channel_; + + // Scoped test versions of required global objects. + ScopedTestDeviceSettingsService device_settings_; + ScopedTestCrosSettings cros_settings_; + system::ScopedFakeStatisticsProvider provider_; + + DISALLOW_COPY_AND_ASSIGN(NetworkScreenUnitTest); +}; + +TEST_F(NetworkScreenUnitTest, ContinuesAutomatically) { + // Verify that we are using the right TaskRunner. + EXPECT_EQ(GetTestMessageLoopTaskRunner()->task_runner(), + base::MessageLoop::current()->task_runner().get()); + + // Set expectation that NetworkScreen will finish. + EXPECT_CALL(mock_base_screen_delegate_, + OnExit(_, ScreenExitCode::NETWORK_CONNECTED, _)) + .Times(1); + + // Simulate a network connection. + EXPECT_CALL(*mock_network_state_helper_, IsConnected()) + .Times(AnyNumber()) + .WillRepeatedly((Return(true))); + network_screen_->UpdateStatus(); + + // Fast forward time by 3 minutes. + FastForwardTime(base::TimeDelta::FromMinutes(3)); + + // Check that we continued once + EXPECT_EQ(1, network_screen_->continue_attempts_); +} + +TEST_F(NetworkScreenUnitTest, ContinuesOnlyOnce) { + // Verify that we are using the right TaskRunner. + EXPECT_EQ(GetTestMessageLoopTaskRunner()->task_runner(), + base::MessageLoop::current()->task_runner().get()); + + // Set expectation that NetworkScreen will finish. + EXPECT_CALL(mock_base_screen_delegate_, + OnExit(_, ScreenExitCode::NETWORK_CONNECTED, _)) + .Times(1); + + // Connect to network "net0". + EXPECT_CALL(*mock_network_state_helper_, GetCurrentNetworkName()) + .Times(AnyNumber()) + .WillRepeatedly(Return(base::ASCIIToUTF16("net0"))); + EXPECT_CALL(*mock_network_state_helper_, IsConnected()) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + + // Stop waiting for net0. + network_screen_->StopWaitingForConnection(base::ASCIIToUTF16("net0")); + + // Fast forward time by 3 minutes. + FastForwardTime(base::TimeDelta::FromMinutes(3)); + + // Check that we have continued exactly once. + ASSERT_EQ(1, network_screen_->continue_attempts_); + + // Stop waiting for another network, net1. + network_screen_->StopWaitingForConnection(base::ASCIIToUTF16("net1")); + + // Fast forward time by 3 minutes. + FastForwardTime(base::TimeDelta::FromMinutes(3)); + + // Check that we have still continued only once. + EXPECT_EQ(1, network_screen_->continue_attempts_); +} + +} // namespace chromeos
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 876ad60..e3e4ea7 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2583,6 +2583,15 @@ "Lock the screen orientation of the device to match video orientation " "when a video goes fullscreen. Only on phones."; +// Video rotate-to-fullscreen experiment strings. + +const char kVideoRotateToFullscreenName[] = + "Rotate-to-fullscreen gesture for videos."; + +const char kVideoRotateToFullscreenDescription[] = + "Enter/exit fullscreen when device is rotated to/from the orientation of " + "the video. Only on phones."; + // Expensive background timer throttling flag const char kExpensiveBackgroundTimerThrottlingName[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index ce8ff8b..0e71765 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2806,6 +2806,14 @@ // playback. extern const char kVideoFullscreenOrientationLockDescription[]; +// Video rotate-to-fullscreen experiment strings. + +// Name of the flag for enabling rotate-to-fullscreen for video playback. +extern const char kVideoRotateToFullscreenName[]; + +// Description of the flag for enabling rotate-to-fullscreen for video playback. +extern const char kVideoRotateToFullscreenDescription[]; + // Expensive background timer throttling flag // Name for the flag to enable expensive background timer throttling
diff --git a/chrome/browser/geolocation/geolocation_settings_state_unittest.cc b/chrome/browser/geolocation/geolocation_settings_state_unittest.cc deleted file mode 100644 index 8c3b6509..0000000 --- a/chrome/browser/geolocation/geolocation_settings_state_unittest.cc +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/geolocation/geolocation_settings_state.h" -#include "chrome/test/base/testing_profile.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "content/public/browser/navigation_details.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gtest/include/gtest/gtest.h" - -using content::NavigationEntry; - -namespace { - -class GeolocationSettingsStateTests : public testing::Test { - public: - GeolocationSettingsStateTests() = default; - - protected: - content::TestBrowserThreadBundle test_browser_thread_bundle_; -}; - -TEST_F(GeolocationSettingsStateTests, ClearOnNewOrigin) { - TestingProfile profile; - GeolocationSettingsState state(&profile); - GURL url_0("http://www.example.com"); - - std::unique_ptr<NavigationEntry> entry(NavigationEntry::Create()); - entry->SetURL(url_0); - content::LoadCommittedDetails load_committed_details; - load_committed_details.entry = entry.get(); - state.DidNavigate(load_committed_details); - - HostContentSettingsMapFactory::GetForProfile(profile) - ->SetContentSettingDefaultScope(url_0, url_0, - CONTENT_SETTINGS_TYPE_GEOLOCATION, - std::string(), CONTENT_SETTING_ALLOW); - state.OnGeolocationPermissionSet(url_0, true); - - GURL url_1("http://www.example1.com"); - HostContentSettingsMapFactory::GetForProfile(profile) - ->SetContentSettingDefaultScope(url_1, url_0, - CONTENT_SETTINGS_TYPE_GEOLOCATION, - std::string(), CONTENT_SETTING_BLOCK); - state.OnGeolocationPermissionSet(url_1, false); - - GeolocationSettingsState::StateMap state_map = - state.state_map(); - EXPECT_EQ(2U, state_map.size()); - - GeolocationSettingsState::FormattedHostsPerState formatted_host_per_state; - unsigned int tab_state_flags = 0; - state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags); - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_ANY_ALLOWED) - << tab_state_flags; - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_EXCEPTION) - << tab_state_flags; - EXPECT_FALSE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_CHANGED) - << tab_state_flags; - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_ANY_ICON) - << tab_state_flags; - EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_0.host())); - - EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_BLOCK].count( - url_1.host())); - - state.OnGeolocationPermissionSet(url_0, false); - - formatted_host_per_state.clear(); - tab_state_flags = 0; - state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags); - EXPECT_FALSE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_ANY_ALLOWED) - << tab_state_flags; - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_EXCEPTION) - << tab_state_flags; - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_CHANGED) - << tab_state_flags; - EXPECT_TRUE(tab_state_flags & - GeolocationSettingsState::TABSTATE_HAS_ANY_ICON) - << tab_state_flags; - EXPECT_EQ(0U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size()); - EXPECT_EQ(2U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_BLOCK].count( - url_0.host())); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_BLOCK].count( - url_1.host())); - - state.OnGeolocationPermissionSet(url_0, true); - - load_committed_details.previous_url = url_0; - state.DidNavigate(load_committed_details); - - GeolocationSettingsState::StateMap new_state_map = - state.state_map(); - EXPECT_EQ(state_map.size(), new_state_map.size()); - - GURL different_url("http://foo.com"); - entry->SetURL(different_url); - state.DidNavigate(load_committed_details); - - EXPECT_TRUE(state.state_map().empty()); - - formatted_host_per_state.clear(); - tab_state_flags = 0; - state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags); - EXPECT_TRUE(formatted_host_per_state.empty()); - EXPECT_EQ(0U, tab_state_flags); -} - -TEST_F(GeolocationSettingsStateTests, ShowPortOnSameHost) { - TestingProfile profile; - GeolocationSettingsState state(&profile); - GURL url_0("http://www.example.com"); - - std::unique_ptr<NavigationEntry> entry(NavigationEntry::Create()); - entry->SetURL(url_0); - content::LoadCommittedDetails load_committed_details; - load_committed_details.entry = entry.get(); - state.DidNavigate(load_committed_details); - - HostContentSettingsMapFactory::GetForProfile(profile) - ->SetContentSettingDefaultScope(url_0, url_0, - CONTENT_SETTINGS_TYPE_GEOLOCATION, - std::string(), CONTENT_SETTING_ALLOW); - state.OnGeolocationPermissionSet(url_0, true); - - GURL url_1("https://www.example.com"); - HostContentSettingsMapFactory::GetForProfile(profile) - ->SetContentSettingDefaultScope(url_1, url_0, - CONTENT_SETTINGS_TYPE_GEOLOCATION, - std::string(), CONTENT_SETTING_ALLOW); - state.OnGeolocationPermissionSet(url_1, true); - - GURL url_2("http://www.example1.com"); - HostContentSettingsMapFactory::GetForProfile(profile) - ->SetContentSettingDefaultScope(url_2, url_0, - CONTENT_SETTINGS_TYPE_GEOLOCATION, - std::string(), CONTENT_SETTING_ALLOW); - state.OnGeolocationPermissionSet(url_2, true); - - GeolocationSettingsState::StateMap state_map = - state.state_map(); - EXPECT_EQ(3U, state_map.size()); - - GeolocationSettingsState::FormattedHostsPerState formatted_host_per_state; - unsigned int tab_state_flags = 0; - state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags); - - EXPECT_EQ(3U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_0.spec())); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_1.spec())); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_2.host())); - - state.OnGeolocationPermissionSet(url_1, false); - formatted_host_per_state.clear(); - tab_state_flags = 0; - state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags); - - EXPECT_EQ(2U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_0.spec())); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_ALLOW].count( - url_2.host())); - EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size()); - EXPECT_EQ(1U, - formatted_host_per_state[CONTENT_SETTING_BLOCK].count( - url_1.spec())); -} - - -} // namespace
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index 2034ad38..33e6b47 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1307,6 +1307,46 @@ CheckElementValue("password", "12345"); } +// https://crbug.com/713645 +// Navigate to a page that can't load some of the subresources. Create a hidden +// form when the body is loaded. Make the form visible. Chrome should autofill +// the form. +// The fact that the form is hidden isn't super important but reproduces the +// actual bug. +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, SlowPageFill) { + // At first let us save a credential to the password store. + scoped_refptr<password_manager::TestPasswordStore> password_store = + static_cast<password_manager::TestPasswordStore*>( + PasswordStoreFactory::GetForProfile( + browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS) + .get()); + autofill::PasswordForm signin_form; + signin_form.signon_realm = embedded_test_server()->base_url().spec(); + signin_form.origin = embedded_test_server()->base_url(); + signin_form.action = embedded_test_server()->base_url(); + signin_form.username_value = base::ASCIIToUTF16("admin"); + signin_form.password_value = base::ASCIIToUTF16("12345"); + password_store->AddLogin(signin_form); + + GURL url = + embedded_test_server()->GetURL("/password/infinite_password_form.html"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_NONE); + + // Wait for autofill. + BubbleObserver bubble_observer(WebContents()); + bubble_observer.WaitForManagementState(); + + // Show the form and make sure that the password was autofilled. + std::string show_form = + "document.getElementsByTagName('form')[0].style.display = 'block'"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), show_form)); + + CheckElementValue("username", "admin"); + CheckElementValue("password", "12345"); +} + // Test that if there was no previous page load then the PasswordManagerDriver // does not think that there were SSL errors on the current page. The test opens // a new tab with a URL for which the embedded test server issues a basic auth
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 72d30e5..2c31e710 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -1039,8 +1039,8 @@ base::SequencedWorkerPool::BLOCK_SHUTDOWN), IsOffTheRecord())); - certificate_report_sender_.reset(new net::ReportSender( - main_request_context_.get(), net::ReportSender::DO_NOT_SEND_COOKIES)); + certificate_report_sender_.reset( + new net::ReportSender(main_request_context_.get())); transport_security_state_->SetReportSender(certificate_report_sender_.get()); expect_ct_reporter_.reset(
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service.cc b/chrome/browser/safe_browsing/certificate_reporting_service.cc index e99cd08b..f75d1ce 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service.cc
@@ -305,15 +305,14 @@ std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter; if (server_public_key) { // Only used in tests. - std::unique_ptr<net::ReportSender> report_sender(new net::ReportSender( - url_request_context, net::ReportSender::DO_NOT_SEND_COOKIES)); + std::unique_ptr<net::ReportSender> report_sender( + new net::ReportSender(url_request_context)); error_reporter.reset(new certificate_reporting::ErrorReporter( GURL(kExtendedReportingUploadUrl), server_public_key, server_public_key_version, std::move(report_sender))); } else { error_reporter.reset(new certificate_reporting::ErrorReporter( - url_request_context, GURL(kExtendedReportingUploadUrl), - net::ReportSender::DO_NOT_SEND_COOKIES)); + url_request_context, GURL(kExtendedReportingUploadUrl))); } reporter_.reset( new Reporter(std::move(error_reporter),
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc index aff63eb..724edb52 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
@@ -205,8 +205,7 @@ net::URLRequestFailedJob::GetMockHttpsUrl(net::ERR_SSL_PROTOCOL_ERROR); certificate_reporting::ErrorReporter* certificate_error_reporter = new certificate_reporting::ErrorReporter( - url_request_context_getter()->GetURLRequestContext(), kFailureURL, - net::ReportSender::DO_NOT_SEND_COOKIES); + url_request_context_getter()->GetURLRequestContext(), kFailureURL); CertificateReportingService::BoundedReportList* list = new CertificateReportingService::BoundedReportList(2); @@ -296,8 +295,7 @@ net::URLRequestFailedJob::GetMockHttpsUrl(net::ERR_SSL_PROTOCOL_ERROR); certificate_reporting::ErrorReporter* certificate_error_reporter = new certificate_reporting::ErrorReporter( - url_request_context_getter()->GetURLRequestContext(), kFailureURL, - net::ReportSender::DO_NOT_SEND_COOKIES); + url_request_context_getter()->GetURLRequestContext(), kFailureURL); CertificateReportingService::BoundedReportList* list = new CertificateReportingService::BoundedReportList(2);
diff --git a/chrome/browser/safe_browsing/mock_permission_report_sender.cc b/chrome/browser/safe_browsing/mock_permission_report_sender.cc index da24f1f..1c6c2c3 100644 --- a/chrome/browser/safe_browsing/mock_permission_report_sender.cc +++ b/chrome/browser/safe_browsing/mock_permission_report_sender.cc
@@ -9,8 +9,7 @@ namespace safe_browsing { MockPermissionReportSender::MockPermissionReportSender() - : net::ReportSender(nullptr, DO_NOT_SEND_COOKIES), - number_of_reports_(0) { + : net::ReportSender(nullptr), number_of_reports_(0) { DCHECK(quit_closure_.is_null()); }
diff --git a/chrome/browser/safe_browsing/notification_image_reporter.cc b/chrome/browser/safe_browsing/notification_image_reporter.cc index b9333b1..93cc487 100644 --- a/chrome/browser/safe_browsing/notification_image_reporter.cc +++ b/chrome/browser/safe_browsing/notification_image_reporter.cc
@@ -59,9 +59,8 @@ NotificationImageReporter::NotificationImageReporter( net::URLRequestContext* request_context) - : NotificationImageReporter(base::MakeUnique<net::ReportSender>( - request_context, - net::ReportSender::CookiesPreference::DO_NOT_SEND_COOKIES)) {} + : NotificationImageReporter( + base::MakeUnique<net::ReportSender>(request_context)) {} NotificationImageReporter::NotificationImageReporter( std::unique_ptr<net::ReportSender> report_sender)
diff --git a/chrome/browser/safe_browsing/permission_reporter.cc b/chrome/browser/safe_browsing/permission_reporter.cc index c4be179..e165dcc 100644 --- a/chrome/browser/safe_browsing/permission_reporter.cc +++ b/chrome/browser/safe_browsing/permission_reporter.cc
@@ -144,11 +144,8 @@ } PermissionReporter::PermissionReporter(net::URLRequestContext* request_context) - : PermissionReporter( - base::MakeUnique<net::ReportSender>( - request_context, - net::ReportSender::CookiesPreference::DO_NOT_SEND_COOKIES), - base::WrapUnique(new base::DefaultClock)) {} + : PermissionReporter(base::MakeUnique<net::ReportSender>(request_context), + base::WrapUnique(new base::DefaultClock)) {} PermissionReporter::PermissionReporter( std::unique_ptr<net::ReportSender> report_sender,
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 340f264..f64dec5 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -562,13 +562,26 @@ if (!rfh) return VISIBILITY_ERROR; - std::unique_ptr<base::Value> value = content::ExecuteScriptAndGetValue( - rfh, "var node = document.getElementById('" + node_id + - "');\n" - "if (node)\n" - " node.offsetWidth > 0 && node.offsetHeight > 0;" - "else\n" - " 'node not found';\n"); + // clang-format off + std::string jsFindVisibility = R"( + (function isNodeVisible(node) { + if (!node) return 'node not found'; + if (node.offsetWidth === 0 || node.offsetHeight === 0) return false; + // Do not check opacity, since the css transition may actually leave + // opacity at 0 after it's been unhidden + if (node.classList.contains('hidden')) return false; + // Otherwise, we must check all parent nodes + var parentVisibility = isNodeVisible(node.parentElement); + if (parentVisibility === 'node not found') { + return true; // none of the parents are set invisible + } + return parentVisibility; + }(document.getElementById(')" + node_id + R"(')));)"; + // clang-format on + + std::unique_ptr<base::Value> value = + content::ExecuteScriptAndGetValue(rfh, jsFindVisibility); + if (!value.get()) return VISIBILITY_ERROR;
diff --git a/chrome/browser/safe_browsing/srt_global_error_win.cc b/chrome/browser/safe_browsing/srt_global_error_win.cc index 7ca6a95..ae8dedd 100644 --- a/chrome/browser/safe_browsing/srt_global_error_win.cc +++ b/chrome/browser/safe_browsing/srt_global_error_win.cc
@@ -13,10 +13,8 @@ #include "base/files/file_util.h" #include "base/path_service.h" #include "base/process/launch.h" -#include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/task_scheduler/post_task.h" -#include "base/threading/thread_task_runner_handle.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" @@ -33,13 +31,8 @@ #include "components/component_updater/pref_names.h" #include "components/prefs/pref_service.h" #include "components/version_info/version_info.h" -#include "content/public/browser/browser_thread.h" #include "ui/base/l10n/l10n_util.h" -using base::SingleThreadTaskRunner; -using base::ThreadTaskRunnerHandle; -using content::BrowserThread; - namespace safe_browsing { namespace { @@ -53,14 +46,11 @@ // downloaded. const base::FilePath::CharType kExecutableExtension[] = L"exe"; -void MaybeExecuteSRTFromBlockingPool( +bool MaybeExecuteSRTFromBlockingPool( const base::FilePath& downloaded_path, bool metrics_enabled, bool sber_enabled, - chrome_cleaner::ChromePromptValue prompt_value, - const scoped_refptr<SingleThreadTaskRunner>& task_runner, - const base::Closure& success_callback, - const base::Closure& failure_callback) { + chrome_cleaner::ChromePromptValue prompt_value) { DCHECK(!downloaded_path.empty()); if (base::PathExists(downloaded_path)) { @@ -96,14 +86,10 @@ base::Process srt_process( base::LaunchProcess(srt_command_line, base::LaunchOptions())); - if (srt_process.IsValid()) { - task_runner->PostTask(FROM_HERE, success_callback); - return; - } + return srt_process.IsValid(); } } - - task_runner->PostTask(FROM_HERE, failure_callback); + return false; } void DeleteFilesFromBlockingPool(const base::FilePath& downloaded_path) { @@ -222,7 +208,7 @@ // At this point, this object owns itself, since ownership has been taken back // from the global_error_service_ in the call to OnUserInteractionStarted. // This means that it is safe to use base::Unretained here. - base::PostTaskWithTraits( + base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, base::TaskTraits().MayBlock().WithPriority( base::TaskPriority::BACKGROUND), @@ -232,12 +218,15 @@ SafeBrowsingExtendedReportingEnabled(), bubble_shown_from_menu_ ? chrome_cleaner::ChromePromptValue::kShownFromMenu - : chrome_cleaner::ChromePromptValue::kPrompted, - base::ThreadTaskRunnerHandle::Get(), - base::Bind(&SRTGlobalError::OnUserinteractionDone, - base::Unretained(this)), - base::Bind(&SRTGlobalError::FallbackToDownloadPage, - base::Unretained(this)))); + : chrome_cleaner::ChromePromptValue::kPrompted), + base::Bind( + [](SRTGlobalError* self, bool success) { + if (success) + self->OnUserinteractionDone(); + else + self->FallbackToDownloadPage(); + }, + base::Unretained(this))); } void SRTGlobalError::FallbackToDownloadPage() {
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter.cc b/chrome/browser/ssl/chrome_expect_ct_reporter.cc index e9e883d..65e338d4 100644 --- a/chrome/browser/ssl/chrome_expect_ct_reporter.cc +++ b/chrome/browser/ssl/chrome_expect_ct_reporter.cc
@@ -116,9 +116,7 @@ ChromeExpectCTReporter::ChromeExpectCTReporter( net::URLRequestContext* request_context) - : report_sender_( - new net::ReportSender(request_context, - net::ReportSender::DO_NOT_SEND_COOKIES)) {} + : report_sender_(new net::ReportSender(request_context)) {} ChromeExpectCTReporter::~ChromeExpectCTReporter() {}
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc b/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc index 225b8b6a..189360e7 100644 --- a/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc +++ b/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc
@@ -35,8 +35,7 @@ // serialized report to be sent. class TestCertificateReportSender : public net::ReportSender { public: - TestCertificateReportSender() - : ReportSender(nullptr, net::ReportSender::DO_NOT_SEND_COOKIES) {} + TestCertificateReportSender() : ReportSender(nullptr) {} ~TestCertificateReportSender() override {} void Send(const GURL& report_uri,
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc index 5ce632f..ad86e76 100644 --- a/chrome/browser/ui/ash/ash_init.cc +++ b/chrome/browser/ui/ash/ash_init.cc
@@ -65,8 +65,10 @@ std::unique_ptr<ash::mus::WindowManager> CreateMusShell() { service_manager::Connector* connector = content::ServiceManagerConnection::GetForProcess()->GetConnector(); + const bool show_primary_host_on_connect = true; std::unique_ptr<ash::mus::WindowManager> window_manager = - base::MakeUnique<ash::mus::WindowManager>(connector, ash::Config::MUS); + base::MakeUnique<ash::mus::WindowManager>(connector, ash::Config::MUS, + show_primary_host_on_connect); // The WindowManager normally deletes the Shell when it loses its connection // to mus. Disable that by installing an empty callback. Chrome installs // its own callback to detect when the connection to mus is lost and that is @@ -75,7 +77,9 @@ std::unique_ptr<aura::WindowTreeClient> window_tree_client = base::MakeUnique<aura::WindowTreeClient>(connector, window_manager.get(), window_manager.get()); - window_tree_client->ConnectAsWindowManager(); + const bool automatically_create_display_roots = false; + window_tree_client->ConnectAsWindowManager( + automatically_create_display_roots); aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client.get()); window_manager->Init(std::move(window_tree_client), content::BrowserThread::GetBlockingPool(),
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index 4936bae1..ce0e044 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -669,6 +669,8 @@ [[tabStripController_ activeTabContentsController] updateFullscreenWidgetFrame]; + [self invalidateTouchBar]; + [self showFullscreenExitBubbleIfNecessary]; browser_->WindowFullscreenStateChanged(); @@ -727,6 +729,8 @@ [self resetCustomAppKitFullscreenVariables]; + [self invalidateTouchBar]; + // Ensures that the permission bubble shows up properly at the front. PermissionRequestManager* manager = [self permissionRequestManager]; if (manager && manager->IsBubbleVisible()) {
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.h b/chrome/browser/ui/cocoa/browser_window_touch_bar.h index 5952600..a65c547 100644 --- a/chrome/browser/ui/cocoa/browser_window_touch_bar.h +++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.h
@@ -22,6 +22,9 @@ // True if the current page is starred. Used by star touch bar button. @property(nonatomic, assign) BOOL isStarred; +// Returns a touch bar item identifier for the given |id|. ++ (NSString*)touchBarIdForItemId:(NSString*)id; + // Designated initializer. - (instancetype)initWithBrowser:(Browser*)browser browserWindowController:(BrowserWindowController*)bwc;
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm index d884dd1..e78d251 100644 --- a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm +++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
@@ -20,6 +20,10 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_command_controller.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" +#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" +#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -28,6 +32,7 @@ #include "components/search_engines/util.h" #include "components/strings/grit/components_strings.h" #include "components/toolbar/vector_icons.h" +#include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util_mac.h" #include "ui/gfx/color_palette.h" @@ -63,6 +68,8 @@ NSString* const kSearchTouchId = @"SEARCH"; NSString* const kStarTouchId = @"BOOKMARK"; NSString* const kNewTabTouchId = @"NEW-TAB"; +NSString* const kExitFullscreenTouchId = @"EXIT-FULLSCREEN"; +NSString* const kFullscreenOriginLabelTouchId = @"FULLSCREEN-ORIGIN-LABEL"; // The button indexes in the back and forward segment control. const int kBackSegmentIndex = 0; @@ -101,16 +108,11 @@ return button; } -NSString* GetTouchBarId(NSString* const touch_bar_id) { +NSString* GetTouchBarId() { NSString* chrome_bundle_id = base::SysUTF8ToNSString(base::mac::BaseBundleID()); - return [NSString stringWithFormat:@"%@.%@", chrome_bundle_id, touch_bar_id]; -} - -NSString* GetTouchBarItemId(NSString* const touch_bar_id, - NSString* const item_id) { return [NSString - stringWithFormat:@"%@-%@", GetTouchBarId(touch_bar_id), item_id]; + stringWithFormat:@"%@.%@", chrome_bundle_id, kBrowserWindowTouchBarId]; } TouchBarAction TouchBarActionFromCommand(int command) { @@ -191,6 +193,10 @@ @synthesize isPageLoading = isPageLoading_; @synthesize isStarred = isStarred_; ++ (NSString*)touchBarIdForItemId:(NSString*)id { + return [NSString stringWithFormat:@"%@-%@", GetTouchBarId(), id]; +} + - (instancetype)initWithBrowser:(Browser*)browser browserWindowController:(BrowserWindowController*)bwc { if ((self = [self init])) { @@ -216,6 +222,25 @@ base::scoped_nsobject<NSTouchBar> touchBar( [[NSClassFromString(@"NSTouchBar") alloc] init]); + [touchBar setCustomizationIdentifier:GetTouchBarId()]; + [touchBar setDelegate:self]; + + // When in tab fullscreen, only the option to exit fullscreen should show up + // on the touch bar since the toolbar is hidden in that state. + if ([bwc_ isFullscreenForTabContentOrExtension]) { + if ([touchBar respondsToSelector: + @selector(setEscapeKeyReplacementItemIdentifier:)]) { + [touchBar setEscapeKeyReplacementItemIdentifier: + [BrowserWindowTouchBar + touchBarIdForItemId:kExitFullscreenTouchId]]; + [touchBar setDefaultItemIdentifiers:@[ + [BrowserWindowTouchBar + touchBarIdForItemId:kFullscreenOriginLabelTouchId] + ]]; + } + return touchBar.autorelease(); + } + NSMutableArray* customIdentifiers = [NSMutableArray arrayWithCapacity:7]; NSMutableArray* defaultIdentifiers = [NSMutableArray arrayWithCapacity:6]; @@ -225,8 +250,7 @@ ]; for (NSString* item in touchBarItems) { - NSString* itemIdentifier = - GetTouchBarItemId(kBrowserWindowTouchBarId, item); + NSString* itemIdentifier = [BrowserWindowTouchBar touchBarIdForItemId:item]; [customIdentifiers addObject:itemIdentifier]; // Don't add the home button if it's not shown in the toolbar. @@ -236,10 +260,8 @@ [customIdentifiers addObject:NSTouchBarItemIdentifierFlexibleSpace]; - [touchBar setCustomizationIdentifier:GetTouchBarId(kBrowserWindowTouchBarId)]; [touchBar setDefaultItemIdentifiers:defaultIdentifiers]; [touchBar setCustomizationAllowedItemIdentifiers:customIdentifiers]; - [touchBar setDelegate:self]; return touchBar.autorelease(); } @@ -294,6 +316,29 @@ [touchBarItem setView:[self searchTouchBarView]]; [touchBarItem setCustomizationLabel:l10n_util::GetNSString( IDS_TOUCH_BAR_GOOGLE_SEARCH)]; + } else if ([identifier hasSuffix:kExitFullscreenTouchId]) { + NSButton* button = [NSButton + buttonWithTitle:l10n_util::GetNSString(IDS_TOUCH_BAR_EXIT_FULLSCREEN) + target:self + action:@selector(exitFullscreenForTab:)]; + [touchBarItem setView:button]; + } else if ([identifier hasSuffix:kFullscreenOriginLabelTouchId]) { + content::WebContents* contents = + browser_->tab_strip_model()->GetActiveWebContents(); + GURL originUrl = contents->GetLastCommittedURL(); + + base::string16 displayText = base::ASCIIToUTF16(originUrl.GetContent()); + size_t hostLength = originUrl.host().length(); + base::scoped_nsobject<NSMutableAttributedString> attributedString( + [[NSMutableAttributedString alloc] + initWithString:base::SysUTF16ToNSString(displayText)]); + [attributedString + addAttribute:NSForegroundColorAttributeName + value:OmniboxViewMac::BaseTextColor(true) + range:NSMakeRange(hostLength, + [attributedString length] - hostLength)]; + [touchBarItem + setView:[NSTextField labelWithAttributedString:attributedString.get()]]; } return touchBarItem.autorelease(); @@ -381,6 +426,12 @@ commandUpdater_->ExecuteCommand(command); } +- (void)exitFullscreenForTab:(id)sender { + browser_->exclusive_access_manager() + ->fullscreen_controller() + ->ExitExclusiveAccessIfNecessary(); +} + - (void)executeCommand:(id)sender { int command = [sender tag]; LogTouchBarUMA(command);
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm index fa9cdff..94b131a 100644 --- a/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm +++ b/chrome/browser/ui/cocoa/browser_window_touch_bar_unittest.mm
@@ -4,72 +4,131 @@ #import <Cocoa/Cocoa.h> +#include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_nsobject.h" +#include "base/strings/sys_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "chrome/app/chrome_command_ids.h" +#import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/browser_window_touch_bar.h" #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "testing/gtest/include/gtest/gtest.h" +#import "third_party/ocmock/OCMock/OCMock.h" class BrowserWindowTouchBarUnitTest : public CocoaProfileTest { public: void SetUp() override { CocoaProfileTest::SetUp(); ASSERT_TRUE(browser()); - browserWindowTouchBar_.reset([[BrowserWindowTouchBar alloc] - initWithBrowser:browser() - browserWindowController:nil]); + + feature_list.InitAndEnableFeature(features::kBrowserTouchBar); + + BOOL yes = YES; + bwc_ = [OCMockObject mockForClass:[BrowserWindowController class]]; + [[[bwc_ stub] andReturnValue:OCMOCK_VALUE(yes)] + isKindOfClass:[BrowserWindowController class]]; + [[bwc_ stub] invalidateTouchBar]; + + touch_bar_.reset([[BrowserWindowTouchBar alloc] initWithBrowser:browser() + browserWindowController:bwc_]); } + id bwc() const { return bwc_; } + void TearDown() override { CocoaProfileTest::TearDown(); } - base::scoped_nsobject<BrowserWindowTouchBar> browserWindowTouchBar_; + // A mock BrowserWindowController object. + id bwc_; + + // Used to enable the the browser window touch bar. + base::test::ScopedFeatureList feature_list; + + base::scoped_nsobject<BrowserWindowTouchBar> touch_bar_; }; +// Tests to check if the touch bar contains the correct items. TEST_F(BrowserWindowTouchBarUnitTest, TouchBarItems) { if (!base::mac::IsAtLeastOS10_12()) return; + BOOL yes = YES; + [[[bwc() expect] andReturnValue:OCMOCK_VALUE(yes)] + isFullscreenForTabContentOrExtension]; + PrefService* prefs = profile()->GetPrefs(); DCHECK(prefs); prefs->SetBoolean(prefs::kShowHomeButton, true); - NSArray* touchBarItemIds = - [[browserWindowTouchBar_ makeTouchBar] itemIdentifiers]; - EXPECT_TRUE([touchBarItemIds containsObject:@"BackForwardTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"ReloadOrStopTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"HomeTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"SearchTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"NewTabTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"StarTouchId"]); + // The touch bar should be empty since the toolbar is hidden when the browser + // is in tab fullscreen. + NSTouchBar* touch_bar = [touch_bar_ makeTouchBar]; + NSArray* touch_bar_items = [touch_bar itemIdentifiers]; + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar + touchBarIdForItemId:@"FULLSCREEN-ORIGIN-LABEL"]]); + EXPECT_TRUE([[touch_bar escapeKeyReplacementItemIdentifier] + isEqualToString:[BrowserWindowTouchBar + touchBarIdForItemId:@"EXIT-FULLSCREEN"]]); + + BOOL no = NO; + [[[bwc() stub] andReturnValue:OCMOCK_VALUE(no)] + isFullscreenForTabContentOrExtension]; + + touch_bar_items = [[touch_bar_ makeTouchBar] itemIdentifiers]; + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"BACK-FWD"]]); + EXPECT_TRUE( + [touch_bar_items containsObject:[BrowserWindowTouchBar + touchBarIdForItemId:@"RELOAD-STOP"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"HOME"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"SEARCH"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"BOOKMARK"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"NEW-TAB"]]); prefs->SetBoolean(prefs::kShowHomeButton, false); - touchBarItemIds = [[browserWindowTouchBar_ makeTouchBar] itemIdentifiers]; - EXPECT_TRUE([touchBarItemIds containsObject:@"BackForwardTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"ReloadOrStopTouchId"]); - EXPECT_FALSE([touchBarItemIds containsObject:@"HomeTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"SearchTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"NewTabTouchId"]); - EXPECT_TRUE([touchBarItemIds containsObject:@"StarTouchId"]); + touch_bar_items = [[touch_bar_ makeTouchBar] itemIdentifiers]; + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"BACK-FWD"]]); + EXPECT_TRUE( + [touch_bar_items containsObject:[BrowserWindowTouchBar + touchBarIdForItemId:@"RELOAD-STOP"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"SEARCH"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"BOOKMARK"]]); + EXPECT_TRUE([touch_bar_items + containsObject:[BrowserWindowTouchBar touchBarIdForItemId:@"NEW-TAB"]]); } +// Tests the reload or stop touch bar item. TEST_F(BrowserWindowTouchBarUnitTest, ReloadOrStopTouchBarItem) { if (!base::mac::IsAtLeastOS10_12()) return; - NSTouchBar* touchBar = [browserWindowTouchBar_ makeTouchBar]; - [browserWindowTouchBar_ setIsPageLoading:NO]; - NSTouchBarItem* item = - [browserWindowTouchBar_ touchBar:touchBar - makeItemForIdentifier:@"ReloadOrStopTouchId"]; + BOOL no = NO; + [[[bwc() stub] andReturnValue:OCMOCK_VALUE(no)] + isFullscreenForTabContentOrExtension]; + NSTouchBar* touch_bar = [touch_bar_ makeTouchBar]; + [touch_bar_ setIsPageLoading:NO]; + + NSTouchBarItem* item = + [touch_bar_ touchBar:touch_bar + makeItemForIdentifier:[BrowserWindowTouchBar + touchBarIdForItemId:@"RELOAD-STOP"]]; EXPECT_EQ(IDC_RELOAD, [[item view] tag]); - [browserWindowTouchBar_ setIsPageLoading:YES]; - item = [browserWindowTouchBar_ touchBar:touchBar - makeItemForIdentifier:@"ReloadOrStopTouchId"]; - + [touch_bar_ setIsPageLoading:YES]; + item = [touch_bar_ touchBar:touch_bar + makeItemForIdentifier:[BrowserWindowTouchBar + touchBarIdForItemId:@"RELOAD-STOP"]]; EXPECT_EQ(IDC_STOP, [[item view] tag]); }
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm index e09ee0d..373f11d 100644 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm +++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -159,9 +159,10 @@ // Flip all frames in RTL. if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { for (NSRect& rect : *decoration_frames) - rect.origin.x = NSWidth(frame) - NSWidth(rect) - NSMinX(rect); - text_frame->origin.x = - NSWidth(frame) - NSWidth(*text_frame) - NSMinX(*text_frame); + rect.origin.x = + NSMinX(frame) + NSMaxX(frame) - NSWidth(rect) - NSMinX(rect); + text_frame->origin.x = NSMinX(frame) + NSMaxX(frame) - + NSWidth(*text_frame) - NSMinX(*text_frame); leading_count = decorations->size() - leading_count; }
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h index f0df678..beaae57e 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
@@ -153,6 +153,11 @@ // different from its frame in the Cocoa sense). void UpdateAccessibilityView(NSRect apparent_frame); + // Computes the real bounds the focus ring should be drawn around for this + // decoration. Some decorations include visual spacing or separators in their + // bounds, but these should not be encompassed by the focus ring. + virtual NSRect GetRealFocusRingBounds(NSRect bounds) const; + DecorationMouseState state() const { return state_; } bool active() const { return active_; }
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm index 5e8d18d..58c2e23 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
@@ -104,7 +104,8 @@ } - (NSRect)focusRingMaskBounds { - return [[self superview] convertRect:apparentFrame_ toView:self]; + return owner_->GetRealFocusRingBounds( + [[self superview] convertRect:apparentFrame_ toView:self]); } @end @@ -184,6 +185,10 @@ [v setApparentFrame:apparent_frame]; } +NSRect LocationBarDecoration::GetRealFocusRingBounds(NSRect bounds) const { + return bounds; +} + void LocationBarDecoration::DrawInFrame(NSRect frame, NSView* control_view) { NOTREACHED(); }
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm index 855e5e1..474a524 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -27,6 +27,7 @@ #import "chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h" #import "chrome/browser/ui/cocoa/first_run_bubble_controller.h" #import "chrome/browser/ui/cocoa/info_bubble_view.h" +#import "chrome/browser/ui/cocoa/l10n_util.h" #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h" @@ -742,6 +743,8 @@ LocationBarDecoration* decoration) { if (!decoration->IsVisible()) return; + // This uses |frame| instead of |bounds| because the accessibility views are + // parented to the toolbar. NSRect apparent_frame = [[field_ cell] frameForDecoration:decoration inFrame:[field_ frame]]; @@ -766,9 +769,13 @@ // before the button preceding the omnibox in the key view order. This // threshold is just a guess. DCHECK_LT(left_index, 10); - if (left_index != -1) - real_frame.origin.x = [field_ frame].origin.x - left_index - 1; - + if (left_index != -1) { + CGFloat delta = left_index + 1; + real_frame.origin.x = + cocoa_l10n_util::ShouldDoExperimentalRTLLayout() + ? NSMaxX([field_ frame]) + delta - NSWidth(real_frame) + : NSMinX([field_ frame]) - delta; + } decoration->UpdateAccessibilityView(apparent_frame); [decoration->GetAccessibilityView() setFrame:real_frame]; [decoration->GetAccessibilityView() setNeedsDisplayInRect:apparent_frame];
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h index 069c6f8..5998b45 100644 --- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h +++ b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h
@@ -73,6 +73,7 @@ bool AcceptsMousePress() override; NSPoint GetBubblePointInFrame(NSRect frame) override; NSString* GetToolTip() override; + NSRect GetRealFocusRingBounds(NSRect apparent_frame) const override; // BubbleDecoration: NSColor* GetBackgroundBorderColor() override; @@ -111,6 +112,11 @@ LocationBarViewMac* owner_; // weak + // Distance in points to inset the right edge of the focus ring by. This is + // used by |GetRealFocusRingBounds| to prevent the focus ring from including + // the divider bar. This is recomputed every time this object is drawn. + int focus_ring_right_inset_ = 0; + // Used to disable find bar animations when testing. bool disable_animations_during_testing_;
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm index 14b40ac..2a8efd6d 100644 --- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm +++ b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
@@ -151,6 +151,7 @@ CGFloat text_left_offset = NSMinX(decoration_frame); CGFloat text_right_offset = NSMaxX(decoration_frame); const BOOL is_rtl = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); + focus_ring_right_inset_ = 0; if (image_) { // The image should fade in if we're animating in. CGFloat image_alpha = @@ -247,6 +248,12 @@ divider_color = [divider_color colorWithAlphaComponent:divider_alpha]; [divider_color set]; [line stroke]; + + focus_ring_right_inset_ = DividerPadding() + line_width; + } else { + // When mouse-hovered, the divider isn't drawn, but the padding for it is + // still present to separate the button from the location bar text. + focus_ring_right_inset_ = DividerPadding(); } } } @@ -292,6 +299,12 @@ stringWithFormat:@"%@. %@", full_label_.get(), tooltip_icon_text]; } +NSRect SecurityStateBubbleDecoration::GetRealFocusRingBounds( + NSRect bounds) const { + bounds.size.width -= focus_ring_right_inset_; + return bounds; +} + ////////////////////////////////////////////////////////////////// // SecurityStateBubbleDecoration::BubbleDecoration:
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index ac5249a..ce37e63 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -90,6 +90,7 @@ #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" #include "ui/views/button_drag_utils.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button_border.h" @@ -121,6 +122,9 @@ // Maximum size of buttons on the bookmark bar. static const int kMaxButtonWidth = 150; +// Corner radius for masking the ink drop effects on buttons. +static const int kInkDropCornerRadius = 2; + // Number of pixels the attached bookmark bar overlaps with the toolbar. static const int kToolbarAttachedBookmarkBarOverlap = 3; @@ -242,6 +246,11 @@ bounds.size(), 0, bounds.CenterPoint(), GetInkDropBaseColor()); } + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { + return base::MakeUnique<views::RoundRectInkDropMask>(size(), kInkDropInsets, + kInkDropCornerRadius); + } + SkColor GetInkDropBaseColor() const override { return GetThemeProvider()->GetColor( ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); @@ -367,6 +376,11 @@ bounds.size(), 0, bounds.CenterPoint(), GetInkDropBaseColor()); } + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { + return base::MakeUnique<views::RoundRectInkDropMask>(size(), kInkDropInsets, + kInkDropCornerRadius); + } + SkColor GetInkDropBaseColor() const override { return GetThemeProvider()->GetColor( ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
diff --git a/chrome/test/data/password/infinite_password_form.html b/chrome/test/data/password/infinite_password_form.html new file mode 100644 index 0000000..70be5af --- /dev/null +++ b/chrome/test/data/password/infinite_password_form.html
@@ -0,0 +1,26 @@ +<!-- +This page has a resource that takes a very long time to load. Nevetheless, a +hidden password form is created dynamically. It should be autofilled and +successful submission should be detected. +--> +<html> + <head> + <script src="form_utils.js"></script> + <script> +function addDynamicForm() { + var form = createSimplePasswordForm(); + form.style.display = 'none'; + document.body.appendChild(form); +} +document.addEventListener("DOMContentLoaded", function(event) { + // Add the form some time after the DOM was loaded. It means that the form + // won't be detected during DidFinishDocumentLoad() stage. + setTimeout(addDynamicForm); +}); + </script> + <title>Test dynamically created password form</title> + </head> + <body> + <img src="/slow?100"> + </body> +</html>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index d69ca5d..65362b3c 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -221,6 +221,9 @@ "RemoteAccessHostClientDomain": { }, + "RemoteAccessHostClientDomainList": { + }, + "RemoteAccessHostFirewallTraversal": { }, @@ -230,6 +233,9 @@ "RemoteAccessHostDomain": { }, + "RemoteAccessHostDomainList": { + }, + "RemoteAccessHostTalkGadgetPrefix": { },
diff --git a/components/about_ui/resources/about_credits.js b/components/about_ui/resources/about_credits.js index d01ffb6..818ef5e7 100644 --- a/components/about_ui/resources/about_credits.js +++ b/components/about_ui/resources/about_credits.js
@@ -23,24 +23,6 @@ } document.addEventListener('DOMContentLoaded', function() { - var licenseEls = [].slice.call(document.getElementsByClassName('product')); - - licenseEls.sort(function(a, b) { - var nameA = a.getElementsByClassName('title')[0].textContent; - var nameB = b.getElementsByClassName('title')[0].textContent; - if (nameA < nameB) return -1; - if (nameA > nameB) return 1; - return 0; - }); - - var parentEl = licenseEls[0].parentNode; - parentEl.innerHTML = ''; - for (var i = 0; i < licenseEls.length; i++) { - parentEl.appendChild(licenseEls[i]); - } - - document.body.hidden = false; - if (cr.isChromeOS) { var keyboardUtils = document.createElement('script'); keyboardUtils.src = 'chrome://credits/keyboard_utils.js';
diff --git a/components/about_ui/resources/about_credits.tmpl b/components/about_ui/resources/about_credits.tmpl index fc4fc965..e9f119d 100644 --- a/components/about_ui/resources/about_credits.tmpl +++ b/components/about_ui/resources/about_credits.tmpl
@@ -59,7 +59,7 @@ } </style> </head> -<body hidden> +<body> <span class="page-title" style="float:left;">Credits</span> <a id="print-link" href="#" style="float:right;">Print</a> <div style="clear:both; overflow:auto;"><!-- Chromium <3s the following projects --> @@ -68,4 +68,4 @@ <script src="chrome://resources/js/cr.js"></script> <script src="chrome://credits/credits.js"></script> </body> -</html> \ No newline at end of file +</html>
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 9be20648..31f24c7 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -737,16 +737,12 @@ } void AutofillAgent::DidAssociateFormControlsDynamically() { - blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); - - // Frame is only processed if it has finished loading, otherwise you can end - // up with a partially parsed form. - if (frame && !frame->IsLoading()) { - ProcessForms(); - password_autofill_agent_->OnDynamicFormsSeen(); - if (password_generation_agent_) - password_generation_agent_->OnDynamicFormsSeen(); - } + // If the control flow is here than the document was at least loaded. The + // whole page doesn't have to be loaded. + ProcessForms(); + password_autofill_agent_->OnDynamicFormsSeen(); + if (password_generation_agent_) + password_generation_agent_->OnDynamicFormsSeen(); } void AutofillAgent::DidCompleteFocusChangeInFrame() {
diff --git a/components/certificate_reporting/error_reporter.cc b/components/certificate_reporting/error_reporter.cc index 6b1e22d..aebdbb7 100644 --- a/components/certificate_reporting/error_reporter.cc +++ b/components/certificate_reporting/error_reporter.cc
@@ -100,15 +100,12 @@ } // namespace -ErrorReporter::ErrorReporter( - net::URLRequestContext* request_context, - const GURL& upload_url, - net::ReportSender::CookiesPreference cookies_preference) +ErrorReporter::ErrorReporter(net::URLRequestContext* request_context, + const GURL& upload_url) : ErrorReporter(upload_url, kServerPublicKey, kServerPublicKeyVersion, - base::MakeUnique<net::ReportSender>(request_context, - cookies_preference)) {} + base::MakeUnique<net::ReportSender>(request_context)) {} ErrorReporter::ErrorReporter( const GURL& upload_url,
diff --git a/components/certificate_reporting/error_reporter.h b/components/certificate_reporting/error_reporter.h index 91afc00f..12ba694 100644 --- a/components/certificate_reporting/error_reporter.h +++ b/components/certificate_reporting/error_reporter.h
@@ -30,11 +30,9 @@ public: // Creates a certificate error reporter that will send certificate // error reports to |upload_url|, using |request_context| as the - // context for the reports. |cookies_preference| controls whether - // cookies will be sent along with the reports. + // context for the reports. ErrorReporter(net::URLRequestContext* request_context, - const GURL& upload_url, - net::ReportSender::CookiesPreference cookies_preference); + const GURL& upload_url); // Allows tests to use a server public key with known private key and // a mock ReportSender. |server_public_key| must outlive
diff --git a/components/certificate_reporting/error_reporter_unittest.cc b/components/certificate_reporting/error_reporter_unittest.cc index 66d84b2..b613788 100644 --- a/components/certificate_reporting/error_reporter_unittest.cc +++ b/components/certificate_reporting/error_reporter_unittest.cc
@@ -51,8 +51,7 @@ // sent. class MockCertificateReportSender : public net::ReportSender { public: - MockCertificateReportSender() - : net::ReportSender(nullptr, DO_NOT_SEND_COOKIES) {} + MockCertificateReportSender() : net::ReportSender(nullptr) {} ~MockCertificateReportSender() override {} void Send(const GURL& report_uri, @@ -179,8 +178,7 @@ const GURL report_uri( net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_FAILED)); - ErrorReporter reporter(&context, report_uri, - net::ReportSender::DO_NOT_SEND_COOKIES); + ErrorReporter reporter(&context, report_uri); bool error_callback_called = false; bool success_callback_called = false; @@ -206,8 +204,7 @@ const GURL report_uri( net::URLRequestMockDataJob::GetMockHttpUrl("some data", 1)); - ErrorReporter reporter(&context, report_uri, - net::ReportSender::DO_NOT_SEND_COOKIES); + ErrorReporter reporter(&context, report_uri); bool error_callback_called = false; bool success_callback_called = false;
diff --git a/components/exo/surface.cc b/components/exo/surface.cc index f186ef9..2c61437 100644 --- a/components/exo/surface.cc +++ b/components/exo/surface.cc
@@ -108,7 +108,9 @@ bool CanFocus() override { return true; } void OnCaptureLost() override {} void OnPaint(const ui::PaintContext& context) override {} - void OnDeviceScaleFactorChanged(float device_scale_factor) override {} + void OnDeviceScaleFactorChanged(float device_scale_factor) override { + surface_->SetDeviceScaleFactor(device_scale_factor); + } void OnWindowDestroying(aura::Window* window) override {} void OnWindowDestroyed(aura::Window* window) override { delete this; } void OnWindowTargetVisibilityChanged(bool visible) override {} @@ -405,6 +407,10 @@ pending_state_.alpha = alpha; } +void Surface::SetDeviceScaleFactor(float device_scale_factor) { + device_scale_factor_ = device_scale_factor; +} + void Surface::Commit() { TRACE_EVENT0("exo", "Surface::Commit"); @@ -847,6 +853,7 @@ current_begin_frame_ack_.has_damage = true; } frame.metadata.begin_frame_ack = current_begin_frame_ack_; + frame.metadata.device_scale_factor = device_scale_factor_; if (current_resource_.id) { // Texture quad is only needed if buffer is not fully transparent.
diff --git a/components/exo/surface.h b/components/exo/surface.h index 1b1bd55..c22029d3 100644 --- a/components/exo/surface.h +++ b/components/exo/surface.h
@@ -140,6 +140,9 @@ // This sets the alpha value that will be applied to the whole surface. void SetAlpha(float alpha); + // This sets the device scale factor sent in CompositorFrames. + void SetDeviceScaleFactor(float device_scale_factor); + // Surface state (damage regions, attached buffers, etc.) is double-buffered. // A Commit() call atomically applies all pending state, replacing the // current state. Commit() is not guaranteed to be synchronous. See @@ -314,6 +317,9 @@ // The buffer that will become the content of surface when Commit() is called. BufferAttachment pending_buffer_; + // The device scale factor sent in CompositorFrames. + float device_scale_factor_ = 1.0f; + const cc::FrameSinkId frame_sink_id_; cc::LocalSurfaceId local_surface_id_;
diff --git a/components/offline_pages/content/suggested_articles_observer.cc b/components/offline_pages/content/suggested_articles_observer.cc index 3479ba8..69d85a07 100644 --- a/components/offline_pages/content/suggested_articles_observer.cc +++ b/components/offline_pages/content/suggested_articles_observer.cc
@@ -76,11 +76,8 @@ auto suggestions_observer = base::MakeUnique<SuggestedArticlesObserver>( browser_context, base::MakeUnique<DefaultDelegate>(service)); service->AddObserver(suggestions_observer.get()); - service->SetUserData( - &kOfflinePageSuggestedArticlesObserverUserDataKey, - // Note that |service| will take ownership of suggestions_observer - // despite accepting a raw pointer. - suggestions_observer.release()); + service->SetUserData(&kOfflinePageSuggestedArticlesObserverUserDataKey, + std::move(suggestions_observer)); } SuggestedArticlesObserver::SuggestedArticlesObserver(
diff --git a/components/offline_pages/content/suggested_articles_observer.h b/components/offline_pages/content/suggested_articles_observer.h index fda1f66f..b8e25d1 100644 --- a/components/offline_pages/content/suggested_articles_observer.h +++ b/components/offline_pages/content/suggested_articles_observer.h
@@ -28,7 +28,7 @@ // specifically. class SuggestedArticlesObserver : public ntp_snippets::ContentSuggestionsService::Observer, - base::SupportsUserData::Data { + public base::SupportsUserData::Data { public: // Delegate exists to allow for dependency injection in unit tests. // SuggestedArticlesObserver implements its own delegate, |DefaultDelegate| in
diff --git a/components/offline_pages/core/background/network_quality_provider_stub.cc b/components/offline_pages/core/background/network_quality_provider_stub.cc index f4243af..9c5cf28 100644 --- a/components/offline_pages/core/background/network_quality_provider_stub.cc +++ b/components/offline_pages/core/background/network_quality_provider_stub.cc
@@ -24,10 +24,10 @@ // static void NetworkQualityProviderStub::SetUserData( base::SupportsUserData* supports_user_data, - NetworkQualityProviderStub* stub) { + std::unique_ptr<NetworkQualityProviderStub> stub) { DCHECK(supports_user_data); DCHECK(stub); - supports_user_data->SetUserData(&kOfflineNQPKey, stub); + supports_user_data->SetUserData(&kOfflineNQPKey, std::move(stub)); } void NetworkQualityProviderStub::AddEffectiveConnectionTypeObserver(
diff --git a/components/offline_pages/core/background/network_quality_provider_stub.h b/components/offline_pages/core/background/network_quality_provider_stub.h index 525e114..54923f023 100644 --- a/components/offline_pages/core/background/network_quality_provider_stub.h +++ b/components/offline_pages/core/background/network_quality_provider_stub.h
@@ -23,7 +23,7 @@ static NetworkQualityProviderStub* GetUserData( base::SupportsUserData* supports_user_data); static void SetUserData(base::SupportsUserData* supports_user_data, - NetworkQualityProviderStub* stub); + std::unique_ptr<NetworkQualityProviderStub> stub); net::EffectiveConnectionType GetEffectiveConnectionType() const override;
diff --git a/components/offline_pages/core/downloads/download_notifying_observer.cc b/components/offline_pages/core/downloads/download_notifying_observer.cc index 00cc67d..648f7f7f 100644 --- a/components/offline_pages/core/downloads/download_notifying_observer.cc +++ b/components/offline_pages/core/downloads/download_notifying_observer.cc
@@ -4,6 +4,7 @@ #include "components/offline_pages/core/downloads/download_notifying_observer.h" +#include "base/memory/ptr_util.h" #include "components/offline_pages/core/background/request_coordinator.h" #include "components/offline_pages/core/background/save_page_request.h" #include "components/offline_pages/core/client_policy_controller.h" @@ -36,11 +37,11 @@ std::unique_ptr<OfflinePageDownloadNotifier> notifier) { DCHECK(request_coordinator); DCHECK(notifier.get()); - DownloadNotifyingObserver* observer = new DownloadNotifyingObserver( - std::move(notifier), request_coordinator->GetPolicyController()); - request_coordinator->AddObserver(observer); - // |request_coordinator| takes ownership of observer here. - request_coordinator->SetUserData(&kUserDataKey, observer); + std::unique_ptr<DownloadNotifyingObserver> observer = + base::WrapUnique(new DownloadNotifyingObserver( + std::move(notifier), request_coordinator->GetPolicyController())); + request_coordinator->AddObserver(observer.get()); + request_coordinator->SetUserData(&kUserDataKey, std::move(observer)); } void DownloadNotifyingObserver::OnAdded(const SavePageRequest& request) {
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.cc b/components/offline_pages/core/downloads/download_ui_adapter.cc index 35910a0f..7e1368ec 100644 --- a/components/offline_pages/core/downloads/download_ui_adapter.cc +++ b/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -32,11 +32,12 @@ } // static -void DownloadUIAdapter::AttachToOfflinePageModel(DownloadUIAdapter* adapter, - OfflinePageModel* model) { +void DownloadUIAdapter::AttachToOfflinePageModel( + std::unique_ptr<DownloadUIAdapter> adapter, + OfflinePageModel* model) { DCHECK(adapter); DCHECK(model); - model->SetUserData(kDownloadUIAdapterKey, adapter); + model->SetUserData(kDownloadUIAdapterKey, std::move(adapter)); } DownloadUIAdapter::ItemInfo::ItemInfo(const OfflinePageItem& page,
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.h b/components/offline_pages/core/downloads/download_ui_adapter.h index 2744f0b..9868fb0 100644 --- a/components/offline_pages/core/downloads/download_ui_adapter.h +++ b/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -83,8 +83,9 @@ ~DownloadUIAdapter() override; static DownloadUIAdapter* FromOfflinePageModel(OfflinePageModel* model); - static void AttachToOfflinePageModel(DownloadUIAdapter* adapter, - OfflinePageModel* model); + static void AttachToOfflinePageModel( + std::unique_ptr<DownloadUIAdapter> adapter, + OfflinePageModel* model); // This adapter is potentially shared by UI elements, each of which adds // itself as an observer.
diff --git a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc b/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc index ebfb511..ab366b53 100644 --- a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc +++ b/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc
@@ -5,6 +5,7 @@ #include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h" #include "base/bind.h" +#include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" #include "components/offline_pages/core/client_policy_controller.h" #include "components/offline_pages/core/offline_page_model.h" @@ -35,7 +36,7 @@ recent_tabs_ui_adapter = new DownloadUIAdapter( offline_page_model, request_coordinator, std::move(delegate)); offline_page_model->SetUserData(kRecentTabsUIAdapterKey, - recent_tabs_ui_adapter); + base::WrapUnique(recent_tabs_ui_adapter)); } return recent_tabs_ui_adapter;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index dd542b6..57a558e9 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -143,7 +143,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 367 +# For your editing convenience: highest ID currently used: 369 # And don't forget to also update the EnterprisePolicies enum of # histograms.xml (run 'python tools/metrics/histograms/update_policies.py'). # @@ -770,17 +770,38 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'deprecated': True, 'example_value': 'my-awesome-domain.com', 'id': 316, 'caption': '''Configure the required domain name for remote access clients''', 'tags': [], - 'desc': '''Configures the required client domain name that will be imposed on remote access clients and prevents users from changing it. + 'desc': '''This policy is deprecated. Please use RemoteAccessHostClientDomainList instead.''', + }, + { + 'name': 'RemoteAccessHostClientDomainList', + 'type': 'list', + 'schema': { + 'type': 'array', + 'items': { 'type': 'string' }, + }, + 'supported_on': ['chrome.*:60-', 'chrome_os:60-'], + 'features': { + 'dynamic_refresh': True, + 'per_profile': False, + }, + 'example_value': ['my-awesome-domain.com', 'my-auxiliary-domain.com'], + 'id': 369, + 'caption': '''Configure the required domain names for remote access clients''', + 'tags': [], + 'desc': '''Configures the required client domain names that will be imposed on remote access clients and prevents users from changing it. - If this setting is enabled, then only clients from the specified domain can connect to the host. + If this setting is enabled, then only clients from one of the specified domains can connect to the host. - If this setting is disabled or not set, then the default policy for the connection type is applied. For remote assistance, this allows clients from any domain can connect to the host; for anytime remote access, only the host owner can connect. + If this setting is disabled or not set, then the default policy for the connection type is applied. For remote assistance, this allows clients from any domain to connect to the host; for anytime remote access, only the host owner can connect. - See also RemoteAccessHostDomain.''', + This setting will override RemoteAccessHostClientDomain, if present. + + See also RemoteAccessHostDomainList.''', }, { 'name': 'RemoteAccessHostFirewallTraversal', @@ -812,17 +833,38 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'deprecated': True, 'example_value': 'my-awesome-domain.com', 'id': 154, 'caption': '''Configure the required domain name for remote access hosts''', 'tags': [], - 'desc': '''Configures the required host domain name that will be imposed on remote access hosts and prevents users from changing it. + 'desc': '''This policy is deprecated. Please use RemoteAccessHostDomainList instead.''', + }, + { + 'name': 'RemoteAccessHostDomainList', + 'type': 'list', + 'schema': { + 'type': 'array', + 'items': {'type': 'string' }, + }, + 'supported_on': ['chrome.*:60-', 'chrome_os:60-'], + 'features': { + 'dynamic_refresh': True, + 'per_profile': False, + }, + 'example_value': ['my-awesome-domain.com', 'my-auxiliary-domain.com'], + 'id': 368, + 'caption': '''Configure the required domain names for remote access hosts''', + 'tags': [], + 'desc': '''Configures the required host domain names that will be imposed on remote access hosts and prevents users from changing it. - If this setting is enabled, then hosts can be shared only using accounts registered on the specified domain name. + If this setting is enabled, then hosts can be shared only using accounts registered on one of the specified domain names. If this setting is disabled or not set, then hosts can be shared using any account. - See also RemoteAccessHostClientDomain.''', + This setting will override RemoteAccessHostDomain, if present. + + See also RemoteAccessHostClientDomainList.''', }, { 'name': 'RemoteAccessHostRequireTwoFactor',
diff --git a/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java b/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java index a36c7bf..83c115d 100644 --- a/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java +++ b/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java
@@ -13,7 +13,6 @@ import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CallbackHelper; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.components.signin.AccountManagerHelper; import org.chromium.components.signin.test.util.AccountHolder; @@ -26,7 +25,6 @@ /** * Tests for AndroidSyncSettings. */ -@DisabledTest(message = "https://crbug.com/605567") public class AndroidSyncSettingsTest extends InstrumentationTestCase { private static class CountingMockSyncContentResolverDelegate extends MockSyncContentResolverDelegate {
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto index 611c16b..49a2d70 100644 --- a/components/sync/protocol/sync.proto +++ b/components/sync/protocol/sync.proto
@@ -179,7 +179,9 @@ // always positive and indentifies the revision of the item data being sent // to the client. // Present in both GetUpdatesResponse and CommitMessage. - required int64 version = 4; + // WARNING: This field used to be required before M60. Any client before this + // will fail to deserialize if this field is missing. + optional int64 version = 4; // Last modification time (in java time milliseconds) // Present in both GetUpdatesResponse and CommitMessage. @@ -197,7 +199,9 @@ // depended on the uniqueness of the property since November 2009; it was // removed from Chromium by http://codereview.chromium.org/371029 . // Present in both GetUpdatesResponse and CommitMessage. - required string name = 7; + // WARNING: This field used to be required before M60. Any client before this + // will fail to deserialize if this field is missing. + optional string name = 7; // The name of this item. Same as |name|. // |non_unique_name| should take precedence over the |name| value if both @@ -965,15 +969,6 @@ optional UserIdentification user = 1; }; -message ThrottleParameters { - // Deprecated. Remove this from the server side. - required int32 min_measure_payload_size = 1; - required double target_utilization = 2; - required double measure_interval_max = 3; - required double measure_interval_min = 4; - required double observation_window = 5; -}; - message ClientToServerResponse { optional CommitResponse commit = 1; optional GetUpdatesResponse get_updates = 2;
diff --git a/components/sync/syncable/directory.cc b/components/sync/syncable/directory.cc index 93732b5..b8cafaf 100644 --- a/components/sync/syncable/directory.cc +++ b/components/sync/syncable/directory.cc
@@ -354,47 +354,50 @@ return std::distance(siblings->begin(), it); } -bool Directory::InsertEntry(BaseWriteTransaction* trans, EntryKernel* entry) { +bool Directory::InsertEntry(BaseWriteTransaction* trans, + std::unique_ptr<EntryKernel> entry) { ScopedKernelLock lock(this); - return InsertEntry(lock, trans, entry); + return InsertEntry(lock, trans, std::move(entry)); } bool Directory::InsertEntry(const ScopedKernelLock& lock, BaseWriteTransaction* trans, - EntryKernel* entry) { + std::unique_ptr<EntryKernel> entry) { if (!SyncAssert(nullptr != entry, FROM_HERE, "Entry is null", trans)) return false; + EntryKernel* entry_ptr = entry.get(); static const char error[] = "Entry already in memory index."; if (!SyncAssert(kernel_->metahandles_map - .insert(std::make_pair(entry->ref(META_HANDLE), - base::WrapUnique(entry))) + .insert(std::make_pair(entry_ptr->ref(META_HANDLE), + std::move(entry))) .second, FROM_HERE, error, trans)) { return false; } if (!SyncAssert( - kernel_->ids_map.insert(std::make_pair(entry->ref(ID).value(), entry)) + kernel_->ids_map + .insert(std::make_pair(entry_ptr->ref(ID).value(), entry_ptr)) .second, FROM_HERE, error, trans)) { return false; } - if (ParentChildIndex::ShouldInclude(entry)) { - if (!SyncAssert(kernel_->parent_child_index.Insert(entry), FROM_HERE, error, - trans)) { + if (ParentChildIndex::ShouldInclude(entry_ptr)) { + if (!SyncAssert(kernel_->parent_child_index.Insert(entry_ptr), FROM_HERE, + error, trans)) { return false; } } - AddToAttachmentIndex(lock, entry->ref(META_HANDLE), - entry->ref(ATTACHMENT_METADATA)); + AddToAttachmentIndex(lock, entry_ptr->ref(META_HANDLE), + entry_ptr->ref(ATTACHMENT_METADATA)); // Should NEVER be created with a client tag or server tag. - if (!SyncAssert(entry->ref(UNIQUE_SERVER_TAG).empty(), FROM_HERE, + if (!SyncAssert(entry_ptr->ref(UNIQUE_SERVER_TAG).empty(), FROM_HERE, "Server tag should be empty", trans)) { return false; } - if (!SyncAssert(entry->ref(UNIQUE_CLIENT_TAG).empty(), FROM_HERE, + if (!SyncAssert(entry_ptr->ref(UNIQUE_CLIENT_TAG).empty(), FROM_HERE, "Client tag should be empty", trans)) return false; @@ -617,17 +620,14 @@ ++i) { MetahandlesMap::iterator found = kernel_->metahandles_map.find((*i)->ref(META_HANDLE)); - EntryKernel* entry = - (found == kernel_->metahandles_map.end() ? nullptr - : found->second.get()); - if (entry && SafeToPurgeFromMemory(&trans, entry)) { + if (found != kernel_->metahandles_map.end() && + SafeToPurgeFromMemory(&trans, found->second.get())) { // We now drop deleted metahandles that are up to date on both the client // and the server. - std::unique_ptr<EntryKernel> unique_entry = std::move(found->second); + std::unique_ptr<EntryKernel> entry = std::move(found->second); size_t num_erased = 0; - num_erased = kernel_->metahandles_map.erase(entry->ref(META_HANDLE)); - DCHECK_EQ(1u, num_erased); + kernel_->metahandles_map.erase(found); num_erased = kernel_->ids_map.erase(entry->ref(ID).value()); DCHECK_EQ(1u, num_erased); if (!entry->ref(UNIQUE_SERVER_TAG).empty()) { @@ -640,8 +640,8 @@ kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG)); DCHECK_EQ(1u, num_erased); } - if (!SyncAssert(!kernel_->parent_child_index.Contains(entry), FROM_HERE, - "Deleted entry still present", (&trans))) + if (!SyncAssert(!kernel_->parent_child_index.Contains(entry.get()), + FROM_HERE, "Deleted entry still present", (&trans))) return false; RemoveFromAttachmentIndex(lock, entry->ref(META_HANDLE), entry->ref(ATTACHMENT_METADATA)); @@ -710,17 +710,18 @@ void Directory::DeleteEntry(const ScopedKernelLock& lock, bool save_to_journal, - EntryKernel* entry, + EntryKernel* entry_ptr, OwnedEntryKernelSet* entries_to_journal) { - int64_t handle = entry->ref(META_HANDLE); - ModelType server_type = - GetModelTypeFromSpecifics(entry->ref(SERVER_SPECIFICS)); + int64_t handle = entry_ptr->ref(META_HANDLE); kernel_->metahandles_to_purge.insert(handle); - std::unique_ptr<EntryKernel> entry_ptr = + std::unique_ptr<EntryKernel> entry = std::move(kernel_->metahandles_map[handle]); + ModelType server_type = + GetModelTypeFromSpecifics(entry->ref(SERVER_SPECIFICS)); + size_t num_erased = 0; num_erased = kernel_->metahandles_map.erase(handle); DCHECK_EQ(1u, num_erased); @@ -730,8 +731,8 @@ DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0); num_erased = kernel_->unapplied_update_metahandles[server_type].erase(handle); DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0); - if (kernel_->parent_child_index.Contains(entry)) - kernel_->parent_child_index.Remove(entry); + if (kernel_->parent_child_index.Contains(entry.get())) + kernel_->parent_child_index.Remove(entry.get()); if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) { num_erased = kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG)); @@ -744,7 +745,7 @@ RemoveFromAttachmentIndex(lock, handle, entry->ref(ATTACHMENT_METADATA)); if (save_to_journal) { - entries_to_journal->insert(std::move(entry_ptr)); + entries_to_journal->insert(std::move(entry)); } }
diff --git a/components/sync/syncable/directory.h b/components/sync/syncable/directory.h index 2911d3d..8204874 100644 --- a/components/sync/syncable/directory.h +++ b/components/sync/syncable/directory.h
@@ -500,7 +500,8 @@ AttachmentIdList* ids); // For new entry creation only. - bool InsertEntry(BaseWriteTransaction* trans, EntryKernel* entry); + bool InsertEntry(BaseWriteTransaction* trans, + std::unique_ptr<EntryKernel> entry); // Update the attachment index for |metahandle| removing it from the index // under |old_metadata| entries and add it under |new_metadata| entries. @@ -557,7 +558,7 @@ bool InsertEntry(const ScopedKernelLock& lock, BaseWriteTransaction* trans, - EntryKernel* entry); + std::unique_ptr<EntryKernel> entry); // Remove each of |metahandle|'s attachment ids from index_by_attachment_id. void RemoveFromAttachmentIndex(
diff --git a/components/sync/syncable/model_neutral_mutable_entry.cc b/components/sync/syncable/model_neutral_mutable_entry.cc index 61eb6fe..8628d422 100644 --- a/components/sync/syncable/model_neutral_mutable_entry.cc +++ b/components/sync/syncable/model_neutral_mutable_entry.cc
@@ -5,6 +5,7 @@ #include "components/sync/syncable/model_neutral_mutable_entry.h" #include <memory> +#include <utility> #include "components/sync/base/hash_util.h" #include "components/sync/base/unique_position.h" @@ -37,12 +38,12 @@ kernel->put(IS_DEL, true); // We match the database defaults here kernel->put(BASE_VERSION, CHANGES_VERSION); - if (!trans->directory()->InsertEntry(trans, kernel.get())) { + kernel_ = kernel.get(); + if (!trans->directory()->InsertEntry(trans, std::move(kernel))) { + kernel_ = nullptr; return; // Failed inserting. } - trans->TrackChangesTo(kernel.get()); - - kernel_ = kernel.release(); + trans->TrackChangesTo(kernel_); } ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans, @@ -74,14 +75,13 @@ kernel->put(IS_DIR, true); kernel->mark_dirty(&trans->directory()->kernel()->dirty_metahandles); + kernel_ = kernel.get(); - if (!trans->directory()->InsertEntry(trans, kernel.get())) { + if (!trans->directory()->InsertEntry(trans, std::move(kernel))) { + kernel_ = nullptr; return; // Failed inserting. } - - trans->TrackChangesTo(kernel.get()); - - kernel_ = kernel.release(); + trans->TrackChangesTo(kernel_); } ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans,
diff --git a/components/sync/syncable/mutable_entry.cc b/components/sync/syncable/mutable_entry.cc index 97a34db..2baa3df 100644 --- a/components/sync/syncable/mutable_entry.cc +++ b/components/sync/syncable/mutable_entry.cc
@@ -4,7 +4,7 @@ #include "components/sync/syncable/mutable_entry.h" -#include <memory> +#include <utility> #include "components/sync/base/hash_util.h" #include "components/sync/base/unique_position.h" @@ -19,55 +19,19 @@ namespace syncer { namespace syncable { -void MutableEntry::Init(WriteTransaction* trans, - ModelType model_type, - const Id& parent_id, - const string& name) { - std::unique_ptr<EntryKernel> kernel(new EntryKernel); - kernel_ = nullptr; - - kernel->put(ID, trans->directory_->NextId()); - kernel->put(META_HANDLE, trans->directory_->NextMetahandle()); - kernel->mark_dirty(&trans->directory_->kernel()->dirty_metahandles); - kernel->put(NON_UNIQUE_NAME, name); - const base::Time& now = base::Time::Now(); - kernel->put(CTIME, now); - kernel->put(MTIME, now); - // We match the database defaults here - kernel->put(BASE_VERSION, CHANGES_VERSION); - - if (!parent_id.IsNull()) { - kernel->put(PARENT_ID, parent_id); - } - - // Normally the SPECIFICS setting code is wrapped in logic to deal with - // unknown fields and encryption. Since all we want to do here is ensure that - // GetModelType() returns a correct value from the very beginning, these - // few lines are sufficient. - sync_pb::EntitySpecifics specifics; - AddDefaultFieldValue(model_type, &specifics); - kernel->put(SPECIFICS, specifics); - - // Because this entry is new, it was originally deleted. - kernel->put(IS_DEL, true); - trans->TrackChangesTo(kernel.get()); - kernel->put(IS_DEL, false); - - // Now swap the pointers. - kernel_ = kernel.release(); -} - MutableEntry::MutableEntry(WriteTransaction* trans, Create, ModelType model_type, const string& name) : ModelNeutralMutableEntry(trans), write_transaction_(trans) { - Init(trans, model_type, Id(), name); + std::unique_ptr<EntryKernel> kernel = + CreateEntryKernel(trans, model_type, Id(), name); + kernel_ = kernel.get(); // We need to have a valid position ready before we can index the item. DCHECK_NE(BOOKMARKS, model_type); DCHECK(!ShouldMaintainPosition()); - bool result = trans->directory()->InsertEntry(trans, kernel_); + bool result = trans->directory()->InsertEntry(trans, std::move(kernel)); DCHECK(result); } @@ -77,7 +41,9 @@ const Id& parent_id, const string& name) : ModelNeutralMutableEntry(trans), write_transaction_(trans) { - Init(trans, model_type, parent_id, name); + std::unique_ptr<EntryKernel> kernel = + CreateEntryKernel(trans, model_type, parent_id, name); + kernel_ = kernel.get(); // We need to have a valid position ready before we can index the item. if (model_type == BOOKMARKS) { // Base the tag off of our cache-guid and local "c-" style ID. @@ -89,7 +55,7 @@ DCHECK(!ShouldMaintainPosition()); } - bool result = trans->directory()->InsertEntry(trans, kernel_); + bool result = trans->directory()->InsertEntry(trans, std::move(kernel)); DCHECK(result); } @@ -303,6 +269,43 @@ MarkForSyncing(this); } +// static +std::unique_ptr<EntryKernel> MutableEntry::CreateEntryKernel( + WriteTransaction* trans, + ModelType model_type, + const Id& parent_id, + const string& name) { + std::unique_ptr<EntryKernel> kernel(new EntryKernel); + + kernel->put(ID, trans->directory_->NextId()); + kernel->put(META_HANDLE, trans->directory_->NextMetahandle()); + kernel->mark_dirty(&trans->directory_->kernel()->dirty_metahandles); + kernel->put(NON_UNIQUE_NAME, name); + const base::Time& now = base::Time::Now(); + kernel->put(CTIME, now); + kernel->put(MTIME, now); + // We match the database defaults here + kernel->put(BASE_VERSION, CHANGES_VERSION); + + if (!parent_id.IsNull()) { + kernel->put(PARENT_ID, parent_id); + } + + // Normally the SPECIFICS setting code is wrapped in logic to deal with + // unknown fields and encryption. Since all we want to do here is ensure that + // GetModelType() returns a correct value from the very beginning, these + // few lines are sufficient. + sync_pb::EntitySpecifics specifics; + AddDefaultFieldValue(model_type, &specifics); + kernel->put(SPECIFICS, specifics); + + // Because this entry is new, it was originally deleted. + kernel->put(IS_DEL, true); + trans->TrackChangesTo(kernel.get()); + kernel->put(IS_DEL, false); + return kernel; +} + // This function sets only the flags needed to get this entry to sync. bool MarkForSyncing(MutableEntry* e) { DCHECK_NE(static_cast<MutableEntry*>(nullptr), e);
diff --git a/components/sync/syncable/mutable_entry.h b/components/sync/syncable/mutable_entry.h index 55cb865..104b78c 100644 --- a/components/sync/syncable/mutable_entry.h +++ b/components/sync/syncable/mutable_entry.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <memory> #include <string> #include "base/macros.h" @@ -26,11 +27,6 @@ // A mutable meta entry. Changes get committed to the database when the // WriteTransaction is destroyed. class MutableEntry : public ModelNeutralMutableEntry { - void Init(WriteTransaction* trans, - ModelType model_type, - const Id& parent_id, - const std::string& name); - public: MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, const Id& id); MutableEntry(WriteTransaction* trans, @@ -77,6 +73,12 @@ const sync_pb::AttachmentIdProto& attachment_id); private: + static std::unique_ptr<EntryKernel> CreateEntryKernel( + WriteTransaction* trans, + ModelType model_type, + const Id& parent_id, + const std::string& name); + // Kind of redundant. We should reduce the number of pointers // floating around if at all possible. Could we store this in Directory? // Scope: Set on construction, never changed after that.
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc index c281e1841..5fc3c272 100644 --- a/content/browser/frame_host/cross_process_frame_connector.cc +++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -183,7 +183,8 @@ void CrossProcessFrameConnector::BubbleScrollEvent( const blink::WebGestureEvent& event) { DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollUpdate || - event.GetType() == blink::WebInputEvent::kGestureScrollEnd); + event.GetType() == blink::WebInputEvent::kGestureScrollEnd || + event.GetType() == blink::WebInputEvent::kGestureFlingStart); auto* parent_view = GetParentRenderWidgetHostView(); if (!parent_view) @@ -203,7 +204,8 @@ if (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) { event_router->BubbleScrollEvent(parent_view, resent_gesture_event); is_scroll_bubbling_ = true; - } else if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd && + } else if ((event.GetType() == blink::WebInputEvent::kGestureScrollEnd || + event.GetType() == blink::WebInputEvent::kGestureFlingStart) && is_scroll_bubbling_) { event_router->BubbleScrollEvent(parent_view, resent_gesture_event); is_scroll_bubbling_ = false;
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 263113a..8c14e80 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -343,8 +343,10 @@ return; if ((event.GetType() == blink::WebInputEvent::kGestureScrollUpdate && not_consumed) || - event.GetType() == blink::WebInputEvent::kGestureScrollEnd) + event.GetType() == blink::WebInputEvent::kGestureScrollEnd || + event.GetType() == blink::WebInputEvent::kGestureFlingStart) { frame_connector_->BubbleScrollEvent(event); + } } void RenderWidgetHostViewChildFrame::DidReceiveCompositorFrameAck(
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index f62cf83..4fd32bc 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -476,6 +476,9 @@ prefs.video_fullscreen_orientation_lock_enabled = base::FeatureList::IsEnabled(media::kVideoFullscreenOrientationLock) && ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE; + prefs.video_rotate_to_fullscreen_enabled = + base::FeatureList::IsEnabled(media::kVideoRotateToFullscreen) && + ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE; #endif prefs.pointer_events_max_touch_points = ui::MaxTouchPoints();
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 232e80d..8631b0c 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1123,12 +1123,11 @@ blink::WebInputEvent::kGestureScrollEnd || gesture_event.GetType() == blink::WebInputEvent::kGestureFlingStart) { - // TODO(wjmaclean): Re-enable the following DCHECK once crbug.com/695187 - // is fixed. - // DCHECK(*is_in_gesture_scroll || - // (gesture_event.type() == blink::WebInputEvent::GestureFlingStart && - // gesture_event.sourceDevice == - // blink::WebGestureDevice::WebGestureDeviceTouchpad)); + DCHECK( + *is_in_gesture_scroll || + (gesture_event.GetType() == blink::WebInputEvent::kGestureFlingStart && + gesture_event.source_device == + blink::WebGestureDevice::kWebGestureDeviceTouchpad)); *is_in_gesture_scroll = false; if (gesture_event.GetType() == blink::WebInputEvent::kGestureFlingStart && gesture_event.source_device ==
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 7f11483..7baa785 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -556,7 +556,8 @@ // including bubbling, based on GestureScrollBegin. DCHECK(target_view); DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollUpdate || - event.GetType() == blink::WebInputEvent::kGestureScrollEnd); + event.GetType() == blink::WebInputEvent::kGestureScrollEnd || + event.GetType() == blink::WebInputEvent::kGestureFlingStart); // DCHECK_XNOR the current and original bubble targets. Both should be set // if a bubbling gesture scroll is in progress. DCHECK(!first_bubbling_scroll_target_.target == @@ -570,7 +571,8 @@ if (target_view == first_bubbling_scroll_target_.target) { bubbling_gesture_scroll_target_.target->ProcessGestureEvent(event, latency_info); - if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd) { + if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd || + event.GetType() == blink::WebInputEvent::kGestureFlingStart) { first_bubbling_scroll_target_.target = nullptr; bubbling_gesture_scroll_target_.target = nullptr; }
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index d8caf50f..7dd1f44 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -940,38 +940,40 @@ } // Class to detect incoming GestureScrollEnd acks for bubbling tests. -class GestureScrollEndObserver +class InputEventAckWaiter : public content::RenderWidgetHost::InputEventObserver { public: - GestureScrollEndObserver() + InputEventAckWaiter(blink::WebInputEvent::Type ack_type_waiting_for) : message_loop_runner_(new content::MessageLoopRunner), - gesture_scroll_end_ack_received_(false) {} - ~GestureScrollEndObserver() override {} + ack_type_waiting_for_(ack_type_waiting_for), + desired_ack_type_received_(false) {} + ~InputEventAckWaiter() override {} void OnInputEventAck(const blink::WebInputEvent& event) override { - if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd) { - gesture_scroll_end_ack_received_ = true; + if (event.GetType() == ack_type_waiting_for_) { + desired_ack_type_received_ = true; if (message_loop_runner_->loop_running()) message_loop_runner_->Quit(); } } void Wait() { - if (!gesture_scroll_end_ack_received_) { + if (!desired_ack_type_received_) { message_loop_runner_->Run(); } } void Reset() { - gesture_scroll_end_ack_received_ = false; + desired_ack_type_received_ = false; message_loop_runner_ = new content::MessageLoopRunner; } private: scoped_refptr<content::MessageLoopRunner> message_loop_runner_; - bool gesture_scroll_end_ack_received_; + blink::WebInputEvent::Type ack_type_waiting_for_; + bool desired_ack_type_received_; - DISALLOW_COPY_AND_ASSIGN(GestureScrollEndObserver); + DISALLOW_COPY_AND_ASSIGN(InputEventAckWaiter); }; // Class to sniff incoming IPCs for FrameHostMsg_FrameRectChanged messages. @@ -1121,6 +1123,75 @@ EXPECT_LT(update_rect.y(), bounds.y() - rwhv_root->GetViewBounds().y()); } +// This test verifies that scroll bubbling from an OOPIF properly forwards +// GestureFlingStart events from the child frame to the parent frame. This +// test times out on failure. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + GestureFlingStartEventsBubble) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + ASSERT_EQ(1U, root->child_count()); + + FrameTreeNode* child_iframe_node = root->child_at(0); + + std::unique_ptr<InputEventAckWaiter> gesture_fling_start_ack_observer = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureFlingStart); + root->current_frame_host()->GetRenderWidgetHost()->AddInputEventObserver( + gesture_fling_start_ack_observer.get()); + + RenderWidgetHost* child_rwh = + child_iframe_node->current_frame_host()->GetRenderWidgetHost(); + + WaitForChildFrameSurfaceReady(child_iframe_node->current_frame_host()); + + gesture_fling_start_ack_observer->Reset(); + // Send a GSB, GSU, GFS sequence and verify that the GFS bubbles. + blink::WebGestureEvent gesture_scroll_begin( + blink::WebGestureEvent::kGestureScrollBegin, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_scroll_begin.data.scroll_begin.delta_hint_units = + blink::WebGestureEvent::ScrollUnits::kPrecisePixels; + gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f; + gesture_scroll_begin.data.scroll_begin.delta_y_hint = 5.f; + + child_rwh->ForwardGestureEvent(gesture_scroll_begin); + + blink::WebGestureEvent gesture_scroll_update( + blink::WebGestureEvent::kGestureScrollUpdate, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_scroll_update.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_scroll_update.data.scroll_update.delta_units = + blink::WebGestureEvent::ScrollUnits::kPrecisePixels; + gesture_scroll_update.data.scroll_update.delta_x = 0.f; + gesture_scroll_update.data.scroll_update.delta_y = 5.f; + gesture_scroll_update.data.scroll_update.velocity_y = 5.f; + + child_rwh->ForwardGestureEvent(gesture_scroll_update); + + blink::WebGestureEvent gesture_fling_start( + blink::WebGestureEvent::kGestureFlingStart, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_fling_start.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_fling_start.data.fling_start.velocity_x = 0.f; + gesture_fling_start.data.fling_start.velocity_y = 5.f; + + child_rwh->ForwardGestureEvent(gesture_fling_start); + + // We now wait for the fling start event to be acked by the parent + // frame. If the test fails, then the test times out. + gesture_fling_start_ack_observer->Wait(); +} + // Test that scrolling a nested out-of-process iframe bubbles unused scroll // delta to a parent frame. #if defined(OS_ANDROID) @@ -1151,8 +1222,9 @@ parent_iframe_node->current_frame_host()->GetProcess()->AddFilter( filter.get()); - std::unique_ptr<GestureScrollEndObserver> ack_observer = - base::MakeUnique<GestureScrollEndObserver>(); + std::unique_ptr<InputEventAckWaiter> ack_observer = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureScrollEnd); parent_iframe_node->current_frame_host() ->GetRenderWidgetHost() ->AddInputEventObserver(ack_observer.get()); @@ -3508,8 +3580,7 @@ } // Verify origin replication with an A-embed-B-embed-C-embed-A hierarchy. -// Disabled due to flake on multiple platforms: https://crbug.com/692864. -IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_OriginReplication) { +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) { GURL main_url(embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)")); EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 3dd2e75..ee8d716 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -239,6 +239,7 @@ IPC_STRUCT_TRAITS_MEMBER(progress_bar_completion) IPC_STRUCT_TRAITS_MEMBER(spellcheck_enabled_by_default) IPC_STRUCT_TRAITS_MEMBER(video_fullscreen_orientation_lock_enabled) + IPC_STRUCT_TRAITS_MEMBER(video_rotate_to_fullscreen_enabled) IPC_STRUCT_TRAITS_MEMBER(video_fullscreen_detection_enabled) IPC_STRUCT_TRAITS_MEMBER(embedded_media_experience_enabled) #else // defined(OS_ANDROID)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 72f7bd8..16ac5ba 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -208,6 +208,7 @@ progress_bar_completion(ProgressBarCompletion::LOAD_EVENT), spellcheck_enabled_by_default(true), video_fullscreen_orientation_lock_enabled(false), + video_rotate_to_fullscreen_enabled(false), video_fullscreen_detection_enabled(false), embedded_media_experience_enabled(false), #else // defined(OS_ANDROID)
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index ae9756c..3d8a224 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -247,6 +247,9 @@ bool spellcheck_enabled_by_default; // If enabled, when a video goes fullscreen, the orientation should be locked. bool video_fullscreen_orientation_lock_enabled; + // If enabled, fullscreen should be entered/exited when the device is rotated + // to/from the orientation of the video. + bool video_rotate_to_fullscreen_enabled; // If enabled, video fullscreen detection will be enabled. bool video_fullscreen_detection_enabled; bool embedded_media_experience_enabled;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 42953f4e..6a17b32 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1050,6 +1050,8 @@ WebRuntimeFeatures::EnableVideoFullscreenOrientationLock( prefs.video_fullscreen_orientation_lock_enabled); + WebRuntimeFeatures::EnableVideoRotateToFullscreen( + prefs.video_rotate_to_fullscreen_enabled); WebRuntimeFeatures::EnableVideoFullscreenDetection( prefs.video_fullscreen_detection_enabled); settings->SetEmbeddedMediaExperienceEnabled(
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index e370326..cd6e821e 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -65,6 +65,8 @@ # Windows only. self.Fail('conformance2/rendering/blitframebuffer-outside-readbuffer.html', ['win', 'd3d11'], bug=644740) + self.Fail('conformance2/textures/misc/tex-base-level-bug.html', + ['win', 'd3d11'], bug=705865) self.Fail('deqp/functional/gles3/sync.html', ['win', 'd3d11'], bug=676848) # Win / NVidia
diff --git a/headless/lib/browser/headless_shell_application_mac.mm b/headless/lib/browser/headless_shell_application_mac.mm index fa8e87a..12c3795 100644 --- a/headless/lib/browser/headless_shell_application_mac.mm +++ b/headless/lib/browser/headless_shell_application_mac.mm
@@ -9,9 +9,8 @@ @implementation HeadlessShellCrApplication - (BOOL)isHandlingSendEvent { - // The CrAppProtocol must return true if [NSApplication sendEvent:] is - // currently on the stack. seee |CrAppProtocol| in |MessagePumpMac|. - return true; + // Since headless mode is non-interactive, always return false. + return false; } @end
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc index 65b183b..c7efc06 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc +++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc
@@ -363,8 +363,8 @@ pool->GetSequenceToken(), base::SequencedWorkerPool::BLOCK_SHUTDOWN), IsOffTheRecord())); - certificate_report_sender_.reset(new net::ReportSender( - main_request_context_.get(), net::ReportSender::DO_NOT_SEND_COOKIES)); + certificate_report_sender_ = + base::MakeUnique<net::ReportSender>(main_request_context_.get()); transport_security_state_->SetReportSender(certificate_report_sender_.get()); // Take ownership over these parameters.
diff --git a/ios/chrome/browser/ui/stack_view/BUILD.gn b/ios/chrome/browser/ui/stack_view/BUILD.gn index dcf3ca52..73868e2 100644 --- a/ios/chrome/browser/ui/stack_view/BUILD.gn +++ b/ios/chrome/browser/ui/stack_view/BUILD.gn
@@ -152,6 +152,7 @@ } source_set("perf_tests") { + configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "stack_view_controller_perftest.mm",
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_controller_perftest.mm b/ios/chrome/browser/ui/stack_view/stack_view_controller_perftest.mm index cb5dbce..c12fe533 100644 --- a/ios/chrome/browser/ui/stack_view/stack_view_controller_perftest.mm +++ b/ios/chrome/browser/ui/stack_view/stack_view_controller_perftest.mm
@@ -20,6 +20,10 @@ #include "ios/web/public/referrer.h" #import "net/base/mac/url_conversions.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + // These tests measure the performance of opening the stack view controller on // an iPhone. On an iPad, the tests do not run, as the iPad does not use the // stack view controller. @@ -53,7 +57,7 @@ BOOL dismissAnimationEnded_; BOOL preloadCardViewsEnded_; @public - BrowserViewController* bvc_; // weak + __weak BrowserViewController* bvc_; } - (void)reinitialize; @@ -166,8 +170,8 @@ reuse_svc_ = false; // The testing delegate will receive stack view animation notifications. - delegate_.reset([[StackViewControllerPerfTestDelegate alloc] - initWithBrowserViewController:bvc_]); + delegate_ = [[StackViewControllerPerfTestDelegate alloc] + initWithBrowserViewController:bvc_]; } void TearDown() override { // Opening a StackViewController is done only on iPhones, not on iPads. @@ -180,8 +184,8 @@ protected: // Stack view controller & delegate. - base::scoped_nsobject<StackViewControllerPerfTestDelegate> delegate_; - base::scoped_nsobject<StackViewController> view_controller_; + StackViewControllerPerfTestDelegate* delegate_; + StackViewController* view_controller_; int current_url_index_; BOOL reuse_svc_; @@ -286,15 +290,15 @@ // which will cache the first snapshot for the tab and reuse it instead of // regenerating a new one each time. [currentTab setSnapshotCoalescingEnabled:YES]; - base::ScopedClosureRunner runner(base::BindBlock(^{ + base::ScopedClosureRunner runner(base::BindBlockArc(^{ [currentTab setSnapshotCoalescingEnabled:NO]; })); if (!view_controller_) { - view_controller_.reset([[StackViewController alloc] - initWithMainTabModel:tab_model_ - otrTabModel:otr_tab_model_ - activeTabModel:tab_model_]); + view_controller_ = + [[StackViewController alloc] initWithMainTabModel:tab_model_ + otrTabModel:otr_tab_model_ + activeTabModel:tab_model_]; } else { [view_controller_ restoreInternalStateWithMainTabModel:tab_model_ otrTabModel:otr_tab_model_ @@ -305,7 +309,7 @@ // The only addition to the function for testing. [view_controller_ setTestDelegate:delegate_]; - [bvc_ presentViewController:view_controller_.get() + [bvc_ presentViewController:view_controller_ animated:NO completion:^{ [view_controller_ showWithSelectedTabAnimation]; @@ -330,7 +334,7 @@ [view_controller_ dismissViewControllerAnimated:NO completion:nil]; if (!reuse_svc_) - view_controller_.reset(); + view_controller_ = nil; base::TimeDelta closeTime = base::Time::NowFromSystemTime() - startTime;
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 1769cff8..ad3fb89 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -219,6 +219,10 @@ const base::Feature kVideoFullscreenOrientationLock{ "VideoFullscreenOrientationLock", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enter/exit fullscreen when device is rotated to/from the video orientation. +const base::Feature kVideoRotateToFullscreen{"VideoRotateToFullscreen", + base::FEATURE_DISABLED_BY_DEFAULT}; + // An experimental feature to enable persistent-license type support in MediaDrm // when using Encrypted Media Extensions (EME) API. // TODO(xhwang): Remove this after feature launch. See http://crbug.com/493521
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index cb502c80..edf1dc88 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -109,6 +109,7 @@ #if defined(OS_ANDROID) MEDIA_EXPORT extern const base::Feature kAndroidMediaPlayerRenderer; MEDIA_EXPORT extern const base::Feature kVideoFullscreenOrientationLock; +MEDIA_EXPORT extern const base::Feature kVideoRotateToFullscreen; MEDIA_EXPORT extern const base::Feature kMediaDrmPersistentLicense; #endif // defined(OS_ANDROID)
diff --git a/net/BUILD.gn b/net/BUILD.gn index 769184d..8bafabe 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1601,8 +1601,6 @@ "spdy/core/spdy_framer_decoder_adapter.h", "spdy/core/spdy_header_block.cc", "spdy/core/spdy_header_block.h", - "spdy/core/spdy_header_indexing.cc", - "spdy/core/spdy_header_indexing.h", "spdy/core/spdy_headers_handler_interface.h", "spdy/core/spdy_pinnable_buffer_piece.cc", "spdy/core/spdy_pinnable_buffer_piece.h", @@ -4787,7 +4785,6 @@ "spdy/core/spdy_frame_reader_test.cc", "spdy/core/spdy_framer_test.cc", "spdy/core/spdy_header_block_test.cc", - "spdy/core/spdy_header_indexing_test.cc", "spdy/core/spdy_no_op_visitor.cc", "spdy/core/spdy_no_op_visitor.h", "spdy/core/spdy_pinnable_buffer_piece_test.cc",
diff --git a/net/docs/bug-triage-suggested-workflow.md b/net/docs/bug-triage-suggested-workflow.md index 147dd8b..3c548e0 100644 --- a/net/docs/bug-triage-suggested-workflow.md +++ b/net/docs/bug-triage-suggested-workflow.md
@@ -49,6 +49,9 @@ ## Investigating component=Internals>Network bugs +* Note that you may want to investigate Needs-Feedback bugs first, as + that may result in some bugs being added to this list. + * It's recommended that while on triage duty, you subscribe to the Internals>Network component (but not its subcomponents). To do this, go to the issue tracker and then click "Saved Queries". @@ -177,6 +180,20 @@ bug. Make sure to indicate if there is a defined point in the past before which the signature is not present. +As an alternative to the above, you can use [Eric Roman's new crash +tool](https://ericroman.users.x20web.corp.google.com/www/net-crash-triage/index.html) +(internal link). Note that it isn't a perfect fit with the triage +responsibilities, specifically: + +* It's only showing Windows releases; Android, iOS, and WebView are + usually different, and Mac is sometimes different. +* The instructions are to look at the latest canary which has a days + worth of data. If canaries are being pushed fast, that may be more + than one canary into the past, and hence not visible on the tool. +* Eric's tool filters based on files in "src/net" rather than looking + for magic signature's including the string "net::" ("src/net" is + probably the better filter). + ## Investigating crashers * Only investigate crashers that are still occurring, as identified by above
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc index cd7e59c3..123a766 100644 --- a/net/quic/core/congestion_control/bbr_sender.cc +++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -553,6 +553,13 @@ // Enter conservation on the first loss. if (has_losses) { recovery_state_ = CONSERVATION; + if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { + // This will cause the |recovery_window_| to be set to the correct + // value in CalculateRecoveryWindow(). + recovery_window_ = 0; + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 1, + 3); + } // Since the conservation phase is meant to be lasting for a whole // round, extend the current round as if it were started right now. current_round_trip_end_ = last_sent_packet_; @@ -712,10 +719,25 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked) { switch (recovery_state_) { case CONSERVATION: - recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; + if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 2, 3); + recovery_window_ = + std::max(unacked_packets_->bytes_in_flight() + bytes_acked, + recovery_window_); + } else { + recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; + } break; case GROWTH: - recovery_window_ = unacked_packets_->bytes_in_flight() + 2 * bytes_acked; + if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 3, 3); + recovery_window_ = + std::max(unacked_packets_->bytes_in_flight() + 2 * bytes_acked, + recovery_window_ + bytes_acked); + } else { + recovery_window_ = + unacked_packets_->bytes_in_flight() + 2 * bytes_acked; + } break; default: break;
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc index 872b863..d5f18394 100644 --- a/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -90,9 +90,14 @@ /*connection_id=*/GetPeerInMemoryConnectionId(43)), receiver_multiplexer_("Receiver multiplexer", {&receiver_, &competing_receiver_}) { + // These will be changed by the appropriate tests as necessary. + FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate = false; + FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery = false; + FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; // TODO(ianswett): Determine why tests become flaky with CWND based on SRTT. FLAGS_quic_reloadable_flag_quic_bbr_base_cwnd_on_srtt = false; FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation = true; + FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation = true; rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats(); sender_ = SetupBbrSender(&bbr_sender_); @@ -315,7 +320,7 @@ // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f); } TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationKeepSending) { @@ -447,8 +452,8 @@ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); // The margin here is high, because the aggregation greatly increases // smoothed rtt. - EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f); + EXPECT_GE(kTestRtt * 5, rtt_stats_->smoothed_rtt()); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.25f); } // Test the number of losses incurred by the startup phase in a situation when @@ -460,7 +465,7 @@ float loss_rate = static_cast<float>(bbr_sender_.connection()->GetStats().packets_lost) / bbr_sender_.connection()->GetStats().packets_sent; - EXPECT_LE(loss_rate, 0.27); + EXPECT_LE(loss_rate, 0.31); } // Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY @@ -490,12 +495,18 @@ ASSERT_EQ(BbrSender::CONSERVATION, sender_->ExportDebugState().recovery_state); + const QuicByteCount cwnd_at_recovery_start = sender_->GetCongestionWindow(); simulator_result = simulator_.RunUntilOrTimeout( - [this]() { + [this, cwnd_at_recovery_start]() { + // Ensure that the CWND never drops due to conservation. + if (sender_->GetCongestionWindow() < cwnd_at_recovery_start) { + return true; + } return sender_->ExportDebugState().recovery_state != BbrSender::CONSERVATION; }, timeout); + ASSERT_GE(sender_->GetCongestionWindow(), cwnd_at_recovery_start); ASSERT_TRUE(simulator_result); ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state);
diff --git a/net/quic/core/crypto/crypto_framer.cc b/net/quic/core/crypto/crypto_framer.cc index b978bf0..77d1bfa4 100644 --- a/net/quic/core/crypto/crypto_framer.cc +++ b/net/quic/core/crypto/crypto_framer.cc
@@ -108,7 +108,7 @@ } std::unique_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), perspective); + QuicDataWriter writer(len, buffer.get(), perspective, HOST_BYTE_ORDER); if (!writer.WriteTag(message.tag())) { DCHECK(false) << "Failed to write message tag."; return nullptr; @@ -197,7 +197,8 @@ Perspective perspective) { // Add this data to the buffer. buffer_.append(input.data(), input.length()); - QuicDataReader reader(buffer_.data(), buffer_.length(), perspective); + QuicDataReader reader(buffer_.data(), buffer_.length(), perspective, + HOST_BYTE_ORDER); switch (state_) { case STATE_READING_TAG:
diff --git a/net/quic/core/crypto/null_decrypter.cc b/net/quic/core/crypto/null_decrypter.cc index 5e0ea06..c42fd34 100644 --- a/net/quic/core/crypto/null_decrypter.cc +++ b/net/quic/core/crypto/null_decrypter.cc
@@ -43,7 +43,8 @@ char* output, size_t* output_length, size_t max_output_length) { - QuicDataReader reader(ciphertext.data(), ciphertext.length(), perspective_); + QuicDataReader reader(ciphertext.data(), ciphertext.length(), perspective_, + HOST_BYTE_ORDER); uint128 hash; if (!ReadHash(&reader, &hash)) {
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc index 59fa781e..0d6e88a 100644 --- a/net/quic/core/quic_connection.cc +++ b/net/quic/core/quic_connection.cc
@@ -49,8 +49,12 @@ const QuicPacketNumber kMaxPacketGap = 5000; // Maximum number of acks received before sending an ack in response. +// TODO(fayang): Remove this constant when deprecating QUIC_VERSION_38. const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; +// Maximum number of consecutive sent nonretransmittable packets. +const QuicPacketCount kMaxConsecutiveNonRetransmittablePackets = 19; + // Maximum number of retransmittable packets received before sending an ack. const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2; // Minimum number of packets received before ack decimation is enabled. @@ -261,7 +265,8 @@ goaway_sent_(false), goaway_received_(false), write_error_occured_(false), - no_stop_waiting_frames_(false) { + no_stop_waiting_frames_(false), + consecutive_num_packets_with_no_retransmittable_frames_(0) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with connection_id: " << connection_id; framer_.set_visitor(this); @@ -933,8 +938,9 @@ ++num_packets_received_since_last_ack_sent_; // Always send an ack every 20 packets in order to allow the peer to discard // information from the SentPacketManager and provide an RTT measurement. - if (num_packets_received_since_last_ack_sent_ >= - kMaxPacketsReceivedBeforeAckSend) { + if (version() <= QUIC_VERSION_38 && + num_packets_received_since_last_ack_sent_ >= + kMaxPacketsReceivedBeforeAckSend) { ack_queued_ = true; } @@ -1660,6 +1666,17 @@ ConnectionCloseSource::FROM_SELF); return; } + + if (version() > QUIC_VERSION_38) { + if (serialized_packet->retransmittable_frames.empty() && + serialized_packet->original_packet_number == 0) { + // Increment consecutive_num_packets_with_no_retransmittable_frames_ if + // this packet is a new transmission with no retransmittable frames. + ++consecutive_num_packets_with_no_retransmittable_frames_; + } else { + consecutive_num_packets_with_no_retransmittable_frames_ = 0; + } + } SendOrQueuePacket(serialized_packet); } @@ -1749,6 +1766,21 @@ num_packets_received_since_last_ack_sent_ = 0; packet_generator_.SetShouldSendAck(!no_stop_waiting_frames_); + if (consecutive_num_packets_with_no_retransmittable_frames_ < + kMaxConsecutiveNonRetransmittablePackets) { + return; + } + consecutive_num_packets_with_no_retransmittable_frames_ = 0; + if (packet_generator_.HasRetransmittableFrames()) { + // There is pending retransmittable frames. + return; + } + + visitor_->OnAckNeedsRetransmittableFrame(); + if (!packet_generator_.HasRetransmittableFrames()) { + // Visitor did not add a retransmittable frame, add a ping frame. + packet_generator_.AddControlFrame(QuicFrame(QuicPingFrame())); + } } void QuicConnection::OnRetransmissionTimeout() {
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h index 0ff9094..ef664ab 100644 --- a/net/quic/core/quic_connection.h +++ b/net/quic/core/quic_connection.h
@@ -141,6 +141,12 @@ // been done. virtual void PostProcessAfterData() = 0; + // Called when the connection sends ack after + // kMaxConsecutiveNonRetransmittablePackets consecutive not retransmittable + // packets sent. To instigate an ack from peer, a retransmittable frame needs + // to be added. + virtual void OnAckNeedsRetransmittableFrame() = 0; + // Called to ask if the visitor wants to schedule write resumption as it both // has pending data to write, and is able to write (e.g. based on flow control // limits). @@ -1082,6 +1088,9 @@ // Indicates not to send or process stop waiting frames. bool no_stop_waiting_frames_; + // Consecutive number of sent packets which have no retransmittable frames. + size_t consecutive_num_packets_with_no_retransmittable_frames_; + DISALLOW_COPY_AND_ASSIGN(QuicConnection); };
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc index 76cf9e4..bc153523 100644 --- a/net/quic/core/quic_connection_test.cc +++ b/net/quic/core/quic_connection_test.cc
@@ -36,6 +36,7 @@ #include "net/quic/test_tools/simple_quic_framer.h" #include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" +#include "testing/gmock_mutant.h" #include "testing/gtest/include/gtest/gtest.h" using std::string; @@ -43,6 +44,7 @@ using testing::AtLeast; using testing::DoAll; using testing::InSequence; +using testing::Invoke; using testing::InvokeWithoutArgs; using testing::NiceMock; using testing::Ref; @@ -389,6 +391,10 @@ return framer_.ping_frames(); } + const std::vector<QuicWindowUpdateFrame>& window_update_frames() const { + return framer_.window_update_frames(); + } + const std::vector<QuicPaddingFrame>& padding_frames() const { return framer_.padding_frames(); } @@ -1499,6 +1505,9 @@ } TEST_P(QuicConnectionTest, 20AcksCausesAckSend) { + if (connection_.version() > QUIC_VERSION_38) { + return; + } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); @@ -1517,6 +1526,54 @@ EXPECT_EQ(2u, writer_->packets_write_attempts()); } +TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { + if (connection_.version() <= QUIC_VERSION_38) { + return; + } + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(99); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(19); + // Receives packets 1 - 39. + for (size_t i = 1; i <= 39; ++i) { + ProcessDataPacket(i); + } + // Receiving Packet 40 causes 20th ack to send. Session is informed and adds + // WINDOW_UPDATE. + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) + .WillOnce( + Invoke(testing::CreateFunctor(&QuicConnection::SendWindowUpdate, + base::Unretained(&connection_), 0, 0))); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_EQ(0u, writer_->window_update_frames().size()); + ProcessDataPacket(40); + EXPECT_EQ(1u, writer_->window_update_frames().size()); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(9); + // Receives packets 41 - 59. + for (size_t i = 41; i <= 59; ++i) { + ProcessDataPacket(i); + } + // Send a packet containing stream frame. + SendStreamDataToPeer(1, "bar", 3, NO_FIN, nullptr); + + // Session will not be informed until receiving another 20 packets. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(19); + for (size_t i = 60; i <= 98; ++i) { + ProcessDataPacket(i); + EXPECT_EQ(0u, writer_->window_update_frames().size()); + } + // Session does not add a retransmittable frame. + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_EQ(0u, writer_->ping_frames().size()); + ProcessDataPacket(99); + EXPECT_EQ(0u, writer_->window_update_frames().size()); + // A ping frame will be added. + EXPECT_EQ(1u, writer_->ping_frames().size()); +} + TEST_P(QuicConnectionTest, LeastUnackedLower) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -1571,6 +1628,7 @@ TEST_P(QuicConnectionTest, TooManyReceivedPackets) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); // Miss 99 of every 100 packets for 5500 packets. for (QuicPacketNumber i = 1; i < kMaxTrackedPackets + 500; i += 100) { ProcessPacket(i); @@ -3687,6 +3745,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); const size_t kMinRttMs = 40; @@ -3742,6 +3801,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -3798,6 +3858,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode( &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); @@ -3862,6 +3923,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode( &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); @@ -3943,6 +4005,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode( &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -4009,6 +4072,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReorderingEighthRtt) { + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode( &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -4342,7 +4406,6 @@ GetPeerInMemoryConnectionId(connection_id_); header.public_header.reset_flag = true; header.public_header.version_flag = false; - header.rejected_packet_number = 10101; std::unique_ptr<QuicEncryptedPacket> packet( framer_.BuildPublicResetPacket(header)); std::unique_ptr<QuicReceivedPacket> received(
diff --git a/net/quic/core/quic_data_reader.cc b/net/quic/core/quic_data_reader.cc index 77ea70a..c748efc 100644 --- a/net/quic/core/quic_data_reader.cc +++ b/net/quic/core/quic_data_reader.cc
@@ -8,32 +8,69 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_bug_tracker.h" -#include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" namespace net { -#define ENDPOINT \ - (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") - QuicDataReader::QuicDataReader(const char* data, const size_t len, - Perspective perspective) - : data_(data), len_(len), pos_(0), perspective_(perspective) { - QUIC_DVLOG(1) << ENDPOINT << "QuicDataReader"; + Perspective perspective, + Endianness endianness) + : data_(data), + len_(len), + pos_(0), + perspective_(perspective), + endianness_(endianness) {} + +bool QuicDataReader::ReadUInt8(uint8_t* result) { + return ReadBytes(result, sizeof(*result)); } bool QuicDataReader::ReadUInt16(uint16_t* result) { - return ReadBytes(result, sizeof(*result)); + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == NETWORK_BYTE_ORDER) { + *result = QuicEndian::NetToHost16(*result); + } + return true; } bool QuicDataReader::ReadUInt32(uint32_t* result) { - return ReadBytes(result, sizeof(*result)); + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == NETWORK_BYTE_ORDER) { + *result = QuicEndian::NetToHost32(*result); + } + return true; } bool QuicDataReader::ReadUInt64(uint64_t* result) { - return ReadBytes(result, sizeof(*result)); + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == NETWORK_BYTE_ORDER) { + *result = QuicEndian::NetToHost64(*result); + } + return true; +} + +bool QuicDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) { + if (num_bytes > sizeof(*result)) { + return false; + } + if (endianness_ == HOST_BYTE_ORDER) { + return ReadBytes(result, num_bytes); + } + + if (!ReadBytes(reinterpret_cast<char*>(result) + sizeof(*result) - num_bytes, + num_bytes)) { + return false; + } + *result = QuicEndian::NetToHost64(*result); + return true; } bool QuicDataReader::ReadUFloat16(uint64_t* result) { @@ -97,7 +134,7 @@ } bool QuicDataReader::ReadConnectionId(uint64_t* connection_id) { - if (!ReadUInt64(connection_id)) { + if (!ReadBytes(connection_id, sizeof(*connection_id))) { return false; }
diff --git a/net/quic/core/quic_data_reader.h b/net/quic/core/quic_data_reader.h index ffce87f..755f2fcc 100644 --- a/net/quic/core/quic_data_reader.h +++ b/net/quic/core/quic_data_reader.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "net/base/int128.h" #include "net/quic/core/quic_types.h" +#include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -33,26 +34,26 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { public: // Caller must provide an underlying buffer to work on. - QuicDataReader(const char* data, const size_t len, Perspective perspective); + QuicDataReader(const char* data, + const size_t len, + Perspective perspective, + Endianness endianness); // Empty destructor. ~QuicDataReader() {} - // Reads a 16-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. + // Reads an 8/16/32/64-bit unsigned integer into the given output + // parameter. Forwards the internal iterator on success. Returns true on + // success, false otherwise. + bool ReadUInt8(uint8_t* result); bool ReadUInt16(uint16_t* result); - - // Reads a 32-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. bool ReadUInt32(uint32_t* result); - - // Reads a 64-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. bool ReadUInt64(uint64_t* result); + // Reads |num_bytes| bytes in the correct byte order into least significant + // bytes of |result|. + bool ReadBytesToUInt64(size_t num_bytes, uint64_t* result); + // Reads a 16-bit unsigned float into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise. @@ -124,6 +125,8 @@ // DOES NOT forward the internal iterator. uint8_t PeekByte() const; + void set_endianness(Endianness endianness) { endianness_ = endianness; } + private: // Returns true if the underlying buffer has enough room to read the given // amount of bytes. @@ -146,6 +149,9 @@ // representation must be consistent. Perspective perspective_; + // The endianness to read integers and floating numbers. + Endianness endianness_; + DISALLOW_COPY_AND_ASSIGN(QuicDataReader); };
diff --git a/net/quic/core/quic_data_writer.cc b/net/quic/core/quic_data_writer.cc index 9b1c426..3290dba 100644 --- a/net/quic/core/quic_data_writer.cc +++ b/net/quic/core/quic_data_writer.cc
@@ -8,21 +8,20 @@ #include <limits> #include "net/quic/core/quic_utils.h" -#include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" namespace net { -#define ENDPOINT \ - (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") - QuicDataWriter::QuicDataWriter(size_t size, char* buffer, - Perspective perspective) - : buffer_(buffer), capacity_(size), length_(0), perspective_(perspective) { - QUIC_DVLOG(1) << ENDPOINT << "QuicDataReader"; -} + Perspective perspective, + Endianness endianness) + : buffer_(buffer), + capacity_(size), + length_(0), + perspective_(perspective), + endianness_(endianness) {} QuicDataWriter::~QuicDataWriter() {} @@ -35,23 +34,39 @@ } bool QuicDataWriter::WriteUInt16(uint16_t value) { + if (endianness_ == NETWORK_BYTE_ORDER) { + value = QuicEndian::HostToNet16(value); + } return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt32(uint32_t value) { + if (endianness_ == NETWORK_BYTE_ORDER) { + value = QuicEndian::HostToNet32(value); + } return WriteBytes(&value, sizeof(value)); } -bool QuicDataWriter::WriteUInt48(uint64_t value) { - uint16_t hi = static_cast<uint16_t>(value >> 32); - uint32_t lo = static_cast<uint32_t>(value); - return WriteUInt32(lo) && WriteUInt16(hi); -} - bool QuicDataWriter::WriteUInt64(uint64_t value) { + if (endianness_ == NETWORK_BYTE_ORDER) { + value = QuicEndian::HostToNet64(value); + } return WriteBytes(&value, sizeof(value)); } +bool QuicDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) { + if (num_bytes > sizeof(value)) { + return false; + } + if (endianness_ == HOST_BYTE_ORDER) { + return WriteBytes(&value, num_bytes); + } + + value = QuicEndian::HostToNet64(value); + return WriteBytes(reinterpret_cast<char*>(&value) + sizeof(value) - num_bytes, + num_bytes); +} + bool QuicDataWriter::WriteUFloat16(uint64_t value) { uint16_t result; if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) { @@ -88,6 +103,9 @@ result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits)); } + if (endianness_ == NETWORK_BYTE_ORDER) { + result = QuicEndian::HostToNet16(result); + } return WriteBytes(&result, sizeof(result)); } @@ -159,7 +177,7 @@ connection_id = QuicEndian::HostToNet64(connection_id); } - return WriteUInt64(connection_id); + return WriteBytes(&connection_id, sizeof(connection_id)); } bool QuicDataWriter::WriteTag(uint32_t tag) {
diff --git a/net/quic/core/quic_data_writer.h b/net/quic/core/quic_data_writer.h index ca4b4a2..8c0f400 100644 --- a/net/quic/core/quic_data_writer.h +++ b/net/quic/core/quic_data_writer.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "net/base/int128.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -25,7 +26,10 @@ class QUIC_EXPORT_PRIVATE QuicDataWriter { public: // Creates a QuicDataWriter where |buffer| is not owned. - QuicDataWriter(size_t size, char* buffer, Perspective perspective); + QuicDataWriter(size_t size, + char* buffer, + Perspective perspective, + Endianness endianness); ~QuicDataWriter(); @@ -36,13 +40,18 @@ char* data(); // Methods for adding to the payload. These values are appended to the end - // of the QuicDataWriter payload. Note - binary integers are written in - // host byte order (little endian) not network byte order (big endian). + // of the QuicDataWriter payload. + + // Writes 8/16/32/64-bit unsigned integers. bool WriteUInt8(uint8_t value); bool WriteUInt16(uint16_t value); bool WriteUInt32(uint32_t value); - bool WriteUInt48(uint64_t value); bool WriteUInt64(uint64_t value); + + // Writes least significant |num_bytes| of a 64-bit unsigned integer in the + // correct byte order. + bool WriteBytesToUInt64(size_t num_bytes, uint64_t value); + // Write unsigned floating point corresponding to the value. Large values are // clamped to the maximum representable (kUFloat16MaxValue). Values that can // not be represented directly are rounded down. @@ -84,6 +93,9 @@ // representation must be consistent. Perspective perspective_; + // The endianness to write integers and floating numbers. + Endianness endianness_; + DISALLOW_COPY_AND_ASSIGN(QuicDataWriter); };
diff --git a/net/quic/core/quic_data_writer_test.cc b/net/quic/core/quic_data_writer_test.cc index 3e32ef9..339c9907 100644 --- a/net/quic/core/quic_data_writer_test.cc +++ b/net/quic/core/quic_data_writer_test.cc
@@ -16,7 +16,34 @@ namespace test { namespace { -class QuicDataWriterTest : public ::testing::TestWithParam<Perspective> {}; +char* AsChars(unsigned char* data) { + return reinterpret_cast<char*>(data); +} + +struct TestParams { + TestParams(Perspective perspective, Endianness endianness) + : perspective(perspective), endianness(endianness) {} + + Perspective perspective; + Endianness endianness; +}; + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + for (Perspective perspective : + {Perspective::IS_CLIENT, Perspective::IS_SERVER}) { + for (Endianness endianness : {NETWORK_BYTE_ORDER, HOST_BYTE_ORDER}) { + params.push_back(TestParams(perspective, endianness)); + } + } + return params; +} + +class QuicDataWriterTest : public ::testing::TestWithParam<TestParams> {}; + +INSTANTIATE_TEST_CASE_P(QuicDataWriterTests, + QuicDataWriterTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicDataWriterTest, SanityCheckUFloat16Consts) { // Check the arithmetic on the constants - otherwise the values below make @@ -99,10 +126,14 @@ for (int i = 0; i < num_test_cases; ++i) { char buffer[2]; - QuicDataWriter writer(2, buffer, GetParam()); + QuicDataWriter writer(2, buffer, GetParam().perspective, + GetParam().endianness); EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded)); - EXPECT_EQ(test_cases[i].encoded, - *reinterpret_cast<uint16_t*>(writer.data())); + uint16_t result = *reinterpret_cast<uint16_t*>(writer.data()); + if (GetParam().endianness == NETWORK_BYTE_ORDER) { + result = QuicEndian::HostToNet16(result); + } + EXPECT_EQ(test_cases[i].encoded, result); } } @@ -159,8 +190,12 @@ int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]); for (int i = 0; i < num_test_cases; ++i) { - QuicDataReader reader(reinterpret_cast<char*>(&test_cases[i].encoded), 2, - GetParam()); + uint16_t encoded_ufloat = test_cases[i].encoded; + if (GetParam().endianness == NETWORK_BYTE_ORDER) { + encoded_ufloat = QuicEndian::HostToNet16(encoded_ufloat); + } + QuicDataReader reader(reinterpret_cast<char*>(&encoded_ufloat), 2, + GetParam().perspective, GetParam().endianness); uint64_t value; EXPECT_TRUE(reader.ReadUFloat16(&value)); EXPECT_EQ(test_cases[i].decoded, value); @@ -172,33 +207,48 @@ uint64_t previous_value = 0; for (uint16_t i = 1; i < 0xFFFF; ++i) { // Read the two bytes. - QuicDataReader reader(reinterpret_cast<char*>(&i), 2, GetParam()); + uint16_t read_number = i; + if (GetParam().endianness == NETWORK_BYTE_ORDER) { + read_number = QuicEndian::HostToNet16(read_number); + } + QuicDataReader reader(reinterpret_cast<char*>(&read_number), 2, + GetParam().perspective, GetParam().endianness); uint64_t value; // All values must be decodable. EXPECT_TRUE(reader.ReadUFloat16(&value)); // Check that small numbers represent themselves - if (i < 4097) + if (i < 4097) { EXPECT_EQ(i, value); + } // Check there's monotonic growth. EXPECT_LT(previous_value, value); // Check that precision is within 0.5% away from the denormals. - if (i > 2000) + if (i > 2000) { EXPECT_GT(previous_value * 1005, value * 1000); + } // Check we're always within the promised range. EXPECT_LT(value, UINT64_C(0x3FFC0000000)); previous_value = value; char buffer[6]; - QuicDataWriter writer(6, buffer, GetParam()); + QuicDataWriter writer(6, buffer, GetParam().perspective, + GetParam().endianness); EXPECT_TRUE(writer.WriteUFloat16(value - 1)); EXPECT_TRUE(writer.WriteUFloat16(value)); EXPECT_TRUE(writer.WriteUFloat16(value + 1)); // Check minimal decoding (previous decoding has previous encoding). - EXPECT_EQ(i - 1, *reinterpret_cast<uint16_t*>(writer.data())); + uint16_t encoded1 = *reinterpret_cast<uint16_t*>(writer.data()); + uint16_t encoded2 = *reinterpret_cast<uint16_t*>(writer.data() + 2); + uint16_t encoded3 = *reinterpret_cast<uint16_t*>(writer.data() + 4); + if (GetParam().endianness == NETWORK_BYTE_ORDER) { + encoded1 = QuicEndian::NetToHost16(encoded1); + encoded2 = QuicEndian::NetToHost16(encoded2); + encoded3 = QuicEndian::NetToHost16(encoded3); + } + EXPECT_EQ(i - 1, encoded1); // Check roundtrip. - EXPECT_EQ(i, *reinterpret_cast<uint16_t*>(writer.data() + 2)); + EXPECT_EQ(i, encoded2); // Check next decoding. - EXPECT_EQ(i < 4096 ? i + 1 : i, - *reinterpret_cast<uint16_t*>(writer.data() + 4)); + EXPECT_EQ(i < 4096 ? i + 1 : i, encoded3); } } @@ -212,16 +262,19 @@ }; const int kBufferLength = sizeof(connection_id); char buffer[kBufferLength]; - QuicDataWriter writer(kBufferLength, buffer, GetParam()); + QuicDataWriter writer(kBufferLength, buffer, GetParam().perspective, + GetParam().endianness); writer.WriteConnectionId(connection_id); test::CompareCharArraysWithHexError( "connection_id", buffer, kBufferLength, - QuicUtils::IsConnectionIdWireFormatBigEndian(GetParam()) ? big_endian - : little_endian, + QuicUtils::IsConnectionIdWireFormatBigEndian(GetParam().perspective) + ? big_endian + : little_endian, kBufferLength); uint64_t read_connection_id; - QuicDataReader reader(buffer, kBufferLength, GetParam()); + QuicDataReader reader(buffer, kBufferLength, GetParam().perspective, + GetParam().endianness); reader.ReadConnectionId(&read_connection_id); EXPECT_EQ(connection_id, read_connection_id); } @@ -232,17 +285,315 @@ }; const int kBufferLength = sizeof(QuicTag); char buffer[kBufferLength]; - QuicDataWriter writer(kBufferLength, buffer, GetParam()); + QuicDataWriter writer(kBufferLength, buffer, GetParam().perspective, + GetParam().endianness); writer.WriteTag(kCHLO); test::CompareCharArraysWithHexError("CHLO", buffer, kBufferLength, CHLO, kBufferLength); QuicTag read_chlo; - QuicDataReader reader(buffer, kBufferLength, GetParam()); + QuicDataReader reader(buffer, kBufferLength, GetParam().perspective, + GetParam().endianness); reader.ReadTag(&read_chlo); EXPECT_EQ(kCHLO, read_chlo); } +TEST_P(QuicDataWriterTest, Write16BitUnsignedIntegers) { + char little_endian16[] = {0x22, 0x11}; + char big_endian16[] = {0x11, 0x22}; + char buffer16[2]; + { + uint16_t in_memory16 = 0x1122; + QuicDataWriter writer(2, buffer16, GetParam().perspective, + GetParam().endianness); + writer.WriteUInt16(in_memory16); + test::CompareCharArraysWithHexError( + "uint16_t", buffer16, 2, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, + 2); + + uint16_t read_number16; + QuicDataReader reader(buffer16, 2, GetParam().perspective, + GetParam().endianness); + reader.ReadUInt16(&read_number16); + EXPECT_EQ(in_memory16, read_number16); + } + + { + uint64_t in_memory16 = 0x0000000000001122; + QuicDataWriter writer(2, buffer16, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(2, in_memory16); + test::CompareCharArraysWithHexError( + "uint16_t", buffer16, 2, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, + 2); + + uint64_t read_number16 = 0u; + QuicDataReader reader(buffer16, 2, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(2, &read_number16); + EXPECT_EQ(in_memory16, read_number16); + } +} + +TEST_P(QuicDataWriterTest, Write24BitUnsignedIntegers) { + char little_endian24[] = {0x33, 0x22, 0x11}; + char big_endian24[] = {0x11, 0x22, 0x33}; + char buffer24[3]; + uint64_t in_memory24 = 0x0000000000112233; + QuicDataWriter writer(3, buffer24, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(3, in_memory24); + test::CompareCharArraysWithHexError( + "uint24", buffer24, 3, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian24 + : little_endian24, + 3); + + uint64_t read_number24 = 0u; + QuicDataReader reader(buffer24, 3, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(3, &read_number24); + EXPECT_EQ(in_memory24, read_number24); +} + +TEST_P(QuicDataWriterTest, Write32BitUnsignedIntegers) { + char little_endian32[] = {0x44, 0x33, 0x22, 0x11}; + char big_endian32[] = {0x11, 0x22, 0x33, 0x44}; + char buffer32[4]; + { + uint32_t in_memory32 = 0x11223344; + QuicDataWriter writer(4, buffer32, GetParam().perspective, + GetParam().endianness); + writer.WriteUInt32(in_memory32); + test::CompareCharArraysWithHexError( + "uint32_t", buffer32, 4, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, + 4); + + uint32_t read_number32; + QuicDataReader reader(buffer32, 4, GetParam().perspective, + GetParam().endianness); + reader.ReadUInt32(&read_number32); + EXPECT_EQ(in_memory32, read_number32); + } + + { + uint64_t in_memory32 = 0x11223344; + QuicDataWriter writer(4, buffer32, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(4, in_memory32); + test::CompareCharArraysWithHexError( + "uint32_t", buffer32, 4, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, + 4); + + uint64_t read_number32 = 0u; + QuicDataReader reader(buffer32, 4, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(4, &read_number32); + EXPECT_EQ(in_memory32, read_number32); + } +} + +TEST_P(QuicDataWriterTest, Write40BitUnsignedIntegers) { + uint64_t in_memory40 = 0x0000001122334455; + char little_endian40[] = {0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian40[] = {0x11, 0x22, 0x33, 0x44, 0x55}; + char buffer40[5]; + QuicDataWriter writer(5, buffer40, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(5, in_memory40); + test::CompareCharArraysWithHexError( + "uint40", buffer40, 5, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian40 + : little_endian40, + 5); + + uint64_t read_number40 = 0u; + QuicDataReader reader(buffer40, 5, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(5, &read_number40); + EXPECT_EQ(in_memory40, read_number40); +} + +TEST_P(QuicDataWriterTest, Write48BitUnsignedIntegers) { + uint64_t in_memory48 = 0x0000112233445566; + char little_endian48[] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian48[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + char buffer48[6]; + QuicDataWriter writer(6, buffer48, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(6, in_memory48); + test::CompareCharArraysWithHexError( + "uint48", buffer48, 6, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian48 + : little_endian48, + 6); + + uint64_t read_number48 = 0u; + QuicDataReader reader(buffer48, 6, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(6., &read_number48); + EXPECT_EQ(in_memory48, read_number48); +} + +TEST_P(QuicDataWriterTest, Write56BitUnsignedIntegers) { + uint64_t in_memory56 = 0x0011223344556677; + char little_endian56[] = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian56[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + char buffer56[7]; + QuicDataWriter writer(7, buffer56, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(7, in_memory56); + test::CompareCharArraysWithHexError( + "uint56", buffer56, 7, + GetParam().endianness == NETWORK_BYTE_ORDER ? big_endian56 + : little_endian56, + 7); + + uint64_t read_number56 = 0u; + QuicDataReader reader(buffer56, 7, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(7, &read_number56); + EXPECT_EQ(in_memory56, read_number56); +} + +TEST_P(QuicDataWriterTest, Write64BitUnsignedIntegers) { + uint64_t in_memory64 = 0x1122334455667788; + unsigned char little_endian64[] = {0x88, 0x77, 0x66, 0x55, + 0x44, 0x33, 0x22, 0x11}; + unsigned char big_endian64[] = {0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88}; + char buffer64[8]; + QuicDataWriter writer(8, buffer64, GetParam().perspective, + GetParam().endianness); + writer.WriteBytesToUInt64(8, in_memory64); + test::CompareCharArraysWithHexError( + "uint64_t", buffer64, 8, + GetParam().endianness == NETWORK_BYTE_ORDER ? AsChars(big_endian64) + : AsChars(little_endian64), + 8); + + uint64_t read_number64 = 0u; + QuicDataReader reader(buffer64, 8, GetParam().perspective, + GetParam().endianness); + reader.ReadBytesToUInt64(8, &read_number64); + EXPECT_EQ(in_memory64, read_number64); + + QuicDataWriter writer2(8, buffer64, GetParam().perspective, + GetParam().endianness); + writer2.WriteUInt64(in_memory64); + test::CompareCharArraysWithHexError( + "uint64_t", buffer64, 8, + GetParam().endianness == NETWORK_BYTE_ORDER ? AsChars(big_endian64) + : AsChars(little_endian64), + 8); + read_number64 = 0u; + QuicDataReader reader2(buffer64, 8, GetParam().perspective, + GetParam().endianness); + reader2.ReadUInt64(&read_number64); + EXPECT_EQ(in_memory64, read_number64); +} + +TEST_P(QuicDataWriterTest, WriteIntegers) { + char buf[43]; + uint8_t i8 = 0x01; + uint16_t i16 = 0x0123; + uint32_t i32 = 0x01234567; + uint64_t i64 = 0x0123456789ABCDEF; + QuicDataWriter writer(46, buf, GetParam().perspective, GetParam().endianness); + for (size_t i = 0; i < 10; ++i) { + switch (i) { + case 0u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 1u: + EXPECT_TRUE(writer.WriteUInt8(i8)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 2u: + EXPECT_TRUE(writer.WriteUInt16(i16)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 3u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 4u: + EXPECT_TRUE(writer.WriteUInt32(i32)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 5u: + case 6u: + case 7u: + case 8u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + default: + EXPECT_FALSE(writer.WriteBytesToUInt64(i, i64)); + } + } + + QuicDataReader reader(buf, 46, GetParam().perspective, GetParam().endianness); + for (size_t i = 0; i < 10; ++i) { + uint8_t read8; + uint16_t read16; + uint32_t read32; + uint64_t read64 = 0u; + switch (i) { + case 0u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0u, read64); + break; + case 1u: + EXPECT_TRUE(reader.ReadUInt8(&read8)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i8, read8); + EXPECT_EQ(0xEFu, read64); + break; + case 2u: + EXPECT_TRUE(reader.ReadUInt16(&read16)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i16, read16); + EXPECT_EQ(0xCDEFu, read64); + break; + case 3u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0xABCDEFu, read64); + break; + case 4u: + EXPECT_TRUE(reader.ReadUInt32(&read32)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i32, read32); + EXPECT_EQ(0x89ABCDEFu, read64); + break; + case 5u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x6789ABCDEFu, read64); + break; + case 6u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x456789ABCDEFu, read64); + break; + case 7u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x23456789ABCDEFu, read64); + break; + case 8u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x0123456789ABCDEFu, read64); + break; + default: + EXPECT_FALSE(reader.ReadBytesToUInt64(i, &read64)); + } + } +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index d1bc575e..59f5072 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -86,12 +86,6 @@ FLAGS_quic_reloadable_flag_quic_create_session_after_insertion, false) -// If true, rejected packet number is removed from public reset packet. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset, - true) - // If true, v33 QUIC client uses 1 bit to specify 8-byte connection id in // public flag. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2, false) @@ -143,7 +137,7 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_one_address_change, false) // If true, multipath bit is not used in public flag. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_multipath_bit, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_multipath_bit, true) // Allow QUIC's flow control autotuning to increase the window as // quickly for the first adjustment as in subsequent ones. @@ -174,7 +168,7 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_38, true) // If true, enable QUIC v39. -QUIC_FLAG(bool, FLAGS_quic_enable_version_39, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_39, false) // If true, on client side, 8-byte connection ID in public header is read and // written in big endian. @@ -217,3 +211,12 @@ // Threshold multiplier below which delivery is considered slow. QUIC_FLAG(double, FLAGS_quic_bbr_slow_delivery_threshold_multiplier, 0.5f) + +// If true, update state if trailing headers with a :final-offset key are +// received for a previously closed QUIC stream. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers, + false) + +// Fix the algorithm used by packet conservation. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation, false)
diff --git a/net/quic/core/quic_flow_controller.cc b/net/quic/core/quic_flow_controller.cc index e95027eb..bf36c7a9 100644 --- a/net/quic/core/quic_flow_controller.cc +++ b/net/quic/core/quic_flow_controller.cc
@@ -202,10 +202,11 @@ } MaybeIncreaseMaxWindowSize(); - SendWindowUpdate(available_window); + UpdateReceiveWindowOffsetAndSendWindowUpdate(available_window); } -void QuicFlowController::SendWindowUpdate(QuicStreamOffset available_window) { +void QuicFlowController::UpdateReceiveWindowOffsetAndSendWindowUpdate( + QuicStreamOffset available_window) { // Update our receive window. receive_window_offset_ += (receive_window_size_ - available_window); @@ -216,8 +217,7 @@ << ", and receive window size: " << receive_window_size_ << ". New receive window offset is: " << receive_window_offset_; - // Inform the peer of our new receive window. - connection_->SendWindowUpdate(id_, receive_window_offset_); + SendWindowUpdate(); } void QuicFlowController::MaybeSendBlocked() { @@ -265,7 +265,7 @@ QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_; IncreaseWindowSize(); - SendWindowUpdate(available_window); + UpdateReceiveWindowOffsetAndSendWindowUpdate(available_window); } bool QuicFlowController::IsBlocked() const { @@ -292,4 +292,8 @@ receive_window_offset_ = size; } +void QuicFlowController::SendWindowUpdate() { + connection_->SendWindowUpdate(id_, receive_window_offset_); +} + } // namespace net
diff --git a/net/quic/core/quic_flow_controller.h b/net/quic/core/quic_flow_controller.h index 97c6fda..f183741a 100644 --- a/net/quic/core/quic_flow_controller.h +++ b/net/quic/core/quic_flow_controller.h
@@ -83,6 +83,9 @@ // Returns true if flow control receive limits have been violated by the peer. bool FlowControlViolation(); + // Inform the peer of new receive window. + void SendWindowUpdate(); + QuicByteCount bytes_consumed() const { return bytes_consumed_; } QuicStreamOffset highest_received_byte_offset() const { @@ -113,7 +116,8 @@ void MaybeIncreaseMaxWindowSize(); // Updates the current offset and sends a window update frame. - void SendWindowUpdate(QuicStreamOffset available_window); + void UpdateReceiveWindowOffsetAndSendWindowUpdate( + QuicStreamOffset available_window); // Double the window size as long as we haven't hit the max window size. void IncreaseWindowSize();
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc index 0fa3442..7404ebb1 100644 --- a/net/quic/core/quic_framer.cc +++ b/net/quic/core/quic_framer.cc
@@ -36,12 +36,6 @@ #define ENDPOINT \ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") -// Mask to select the lowest 48 bits of a packet number. -const QuicPacketNumber k6ByteSequenceNumberMask = UINT64_C(0x0000FFFFFFFFFFFF); -const QuicPacketNumber k4ByteSequenceNumberMask = UINT64_C(0x00000000FFFFFFFF); -const QuicPacketNumber k2ByteSequenceNumberMask = UINT64_C(0x000000000000FFFF); -const QuicPacketNumber k1ByteSequenceNumberMask = UINT64_C(0x00000000000000FF); - // Number of bits the packet number length bits are shifted from the right // edge of the public header. const uint8_t kPublicHeaderSequenceNumberShift = 4; @@ -319,7 +313,7 @@ const QuicFrames& frames, char* buffer, size_t packet_length) { - QuicDataWriter writer(packet_length, buffer, perspective_); + QuicDataWriter writer(packet_length, buffer, perspective_, endianness()); if (!AppendPacketHeader(header, &writer)) { QUIC_BUG << "AppendPacketHeader failed"; return 0; @@ -417,9 +411,6 @@ CryptoHandshakeMessage reset; reset.set_tag(kPRST); reset.SetValue(kRNON, packet.nonce_proof); - if (!FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset) { - reset.SetValue(kRSEQ, packet.rejected_packet_number); - } if (packet.client_address.host().address_family() != IpAddressFamily::IP_UNSPEC) { // packet.client_address is non-empty. @@ -436,7 +427,10 @@ size_t len = kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID + reset_serialized.length(); std::unique_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), Perspective::IS_SERVER); + // Endianness is not a concern here, as writer is not going to write integers + // or floating numbers. + QuicDataWriter writer(len, buffer.get(), Perspective::IS_SERVER, + NETWORK_BYTE_ORDER); uint8_t flags = static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_RST | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID); @@ -466,7 +460,10 @@ DCHECK(!versions.empty()); size_t len = GetVersionNegotiationPacketSize(versions.size()); std::unique_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), Perspective::IS_SERVER); + // Endianness is not a concern here, version negotiation packet does not have + // integers or floating numbers. + QuicDataWriter writer(len, buffer.get(), Perspective::IS_SERVER, + NETWORK_BYTE_ORDER); uint8_t flags = static_cast<uint8_t>( PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID | @@ -490,7 +487,8 @@ } bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { - QuicDataReader reader(packet.data(), packet.length(), perspective_); + QuicDataReader reader(packet.data(), packet.length(), perspective_, + endianness()); visitor_->OnPacket(); @@ -516,6 +514,9 @@ } } + // framer's version may change, reset reader's endianness. + reader.set_endianness(endianness()); + bool rv; if (perspective_ == Perspective::IS_CLIENT && public_header.version_flag) { rv = ProcessVersionNegotiationPacket(&reader, &public_header); @@ -578,7 +579,8 @@ return RaiseError(QUIC_DECRYPTION_FAILURE); } - QuicDataReader reader(decrypted_buffer, decrypted_length, perspective_); + QuicDataReader reader(decrypted_buffer, decrypted_length, perspective_, + endianness()); // Set the last packet number after we have decrypted the packet // so we are confident is not attacker controlled. @@ -658,7 +660,7 @@ } public_flags |= - GetSequenceNumberFlags(header.public_header.packet_number_length) + GetPacketNumberFlags(header.public_header.packet_number_length) << kPublicHeaderSequenceNumberShift; if (header.public_header.nonce != nullptr) { @@ -703,8 +705,8 @@ return false; } - if (!AppendPacketSequenceNumber(header.public_header.packet_number_length, - header.packet_number, writer)) { + if (!AppendPacketNumber(header.public_header.packet_number_length, + header.packet_number, writer)) { return false; } @@ -860,7 +862,7 @@ } // static -QuicPacketNumberLength QuicFramer::GetMinSequenceNumberLength( +QuicPacketNumberLength QuicFramer::GetMinPacketNumberLength( QuicPacketNumber packet_number) { if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) { return PACKET_1BYTE_PACKET_NUMBER; @@ -874,7 +876,7 @@ } // static -uint8_t QuicFramer::GetSequenceNumberFlags( +uint8_t QuicFramer::GetPacketNumberFlags( QuicPacketNumberLength packet_number_length) { switch (packet_number_length) { case PACKET_1BYTE_PACKET_NUMBER: @@ -926,7 +928,7 @@ QuicPacketHeader* header) { QuicPacketNumber base_packet_number = largest_packet_number_; - if (!ProcessPacketSequenceNumber( + if (!ProcessAndCalculatePacketNumber( encrypted_reader, header->public_header.packet_number_length, base_packet_number, &header->packet_number)) { set_detailed_error("Unable to read packet number."); @@ -946,13 +948,13 @@ return true; } -bool QuicFramer::ProcessPacketSequenceNumber( +bool QuicFramer::ProcessAndCalculatePacketNumber( QuicDataReader* reader, QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number, QuicPacketNumber* packet_number) { QuicPacketNumber wire_packet_number = 0u; - if (!reader->ReadBytes(&wire_packet_number, packet_number_length)) { + if (!reader->ReadBytesToUInt64(packet_number_length, &wire_packet_number)) { return false; } @@ -1157,14 +1159,15 @@ frame->fin = (stream_flags & kQuicStreamFinMask) == kQuicStreamFinShift; - frame->stream_id = 0; - if (!reader->ReadBytes(&frame->stream_id, stream_id_length)) { + uint64_t stream_id = 0; + if (!reader->ReadBytesToUInt64(stream_id_length, &stream_id)) { set_detailed_error("Unable to read stream_id."); return false; } + frame->stream_id = static_cast<QuicStreamId>(stream_id); frame->offset = 0; - if (!reader->ReadBytes(&frame->offset, offset_length)) { + if (!reader->ReadBytesToUInt64(offset_length, &frame->offset)) { set_detailed_error("Unable to read offset."); return false; } @@ -1202,7 +1205,8 @@ frame_type >>= kQuicHasMultipleAckBlocksShift; bool has_ack_blocks = frame_type & kQuicHasMultipleAckBlocksMask; - if (!reader->ReadBytes(&ack_frame->largest_observed, largest_acked_length)) { + if (!reader->ReadBytesToUInt64(largest_acked_length, + &ack_frame->largest_observed)) { set_detailed_error("Unable to read largest acked."); return false; } @@ -1222,14 +1226,14 @@ uint8_t num_ack_blocks = 0; if (has_ack_blocks) { - if (!reader->ReadBytes(&num_ack_blocks, 1)) { + if (!reader->ReadUInt8(&num_ack_blocks)) { set_detailed_error("Unable to read num of ack blocks."); return false; } } - size_t first_block_length = 0; - if (!reader->ReadBytes(&first_block_length, ack_block_length)) { + uint64_t first_block_length = 0; + if (!reader->ReadBytesToUInt64(ack_block_length, &first_block_length)) { set_detailed_error("Unable to read first ack block length."); return false; } @@ -1239,13 +1243,13 @@ if (num_ack_blocks > 0) { for (size_t i = 0; i < num_ack_blocks; ++i) { - size_t gap = 0; - if (!reader->ReadBytes(&gap, PACKET_1BYTE_PACKET_NUMBER)) { + uint8_t gap = 0; + if (!reader->ReadUInt8(&gap)) { set_detailed_error("Unable to read gap to next ack block."); return false; } - size_t current_block_length = 0; - if (!reader->ReadBytes(¤t_block_length, ack_block_length)) { + uint64_t current_block_length = 0; + if (!reader->ReadBytesToUInt64(ack_block_length, ¤t_block_length)) { set_detailed_error("Unable to ack block length."); return false; } @@ -1267,15 +1271,14 @@ bool QuicFramer::ProcessTimestampsInAckFrame(QuicDataReader* reader, QuicAckFrame* ack_frame) { uint8_t num_received_packets; - if (!reader->ReadBytes(&num_received_packets, 1)) { + if (!reader->ReadUInt8(&num_received_packets)) { set_detailed_error("Unable to read num received packets."); return false; } if (num_received_packets > 0) { uint8_t delta_from_largest_observed; - if (!reader->ReadBytes(&delta_from_largest_observed, - PACKET_1BYTE_PACKET_NUMBER)) { + if (!reader->ReadUInt8(&delta_from_largest_observed)) { set_detailed_error("Unable to read sequence delta in received packets."); return false; } @@ -1284,7 +1287,7 @@ // Time delta from the framer creation. uint32_t time_delta_us; - if (!reader->ReadBytes(&time_delta_us, sizeof(time_delta_us))) { + if (!reader->ReadUInt32(&time_delta_us)) { set_detailed_error("Unable to read time delta in received packets."); return false; } @@ -1296,8 +1299,7 @@ std::make_pair(seq_num, creation_time_ + last_timestamp_)); for (uint8_t i = 1; i < num_received_packets; ++i) { - if (!reader->ReadBytes(&delta_from_largest_observed, - PACKET_1BYTE_PACKET_NUMBER)) { + if (!reader->ReadUInt8(&delta_from_largest_observed)) { set_detailed_error( "Unable to read sequence delta in received packets."); return false; @@ -1325,8 +1327,8 @@ const QuicPacketHeader& header, QuicStopWaitingFrame* stop_waiting) { QuicPacketNumber least_unacked_delta = 0; - if (!reader->ReadBytes(&least_unacked_delta, - header.public_header.packet_number_length)) { + if (!reader->ReadBytesToUInt64(header.public_header.packet_number_length, + &least_unacked_delta)) { set_detailed_error("Unable to read least unacked delta."); return false; } @@ -1651,9 +1653,9 @@ AckFrameInfo ack_info = GetAckFrameInfo(ack); QuicPacketNumberLength largest_acked_length = - GetMinSequenceNumberLength(ack.largest_observed); + GetMinPacketNumberLength(ack.largest_observed); QuicPacketNumberLength ack_block_length = - GetMinSequenceNumberLength(ack_info.max_block_length); + GetMinPacketNumberLength(ack_info.max_block_length); ack_size = GetMinAckFrameSize(quic_version_, largest_acked_length); // First ack block length. @@ -1757,32 +1759,38 @@ } // static -bool QuicFramer::AppendPacketSequenceNumber( - QuicPacketNumberLength packet_number_length, - QuicPacketNumber packet_number, - QuicDataWriter* writer) { - // Ensure the entire packet number can be written. - if (writer->capacity() - writer->length() < - static_cast<size_t>(packet_number_length)) { +bool QuicFramer::AppendPacketNumber(QuicPacketNumberLength packet_number_length, + QuicPacketNumber packet_number, + QuicDataWriter* writer) { + size_t length = packet_number_length; + if (length != 1 && length != 2 && length != 4 && length != 6) { + QUIC_BUG << "Invalid packet_number_length: " << length; return false; } - switch (packet_number_length) { - case PACKET_1BYTE_PACKET_NUMBER: - return writer->WriteUInt8(packet_number & k1ByteSequenceNumberMask); - break; - case PACKET_2BYTE_PACKET_NUMBER: - return writer->WriteUInt16(packet_number & k2ByteSequenceNumberMask); - break; - case PACKET_4BYTE_PACKET_NUMBER: - return writer->WriteUInt32(packet_number & k4ByteSequenceNumberMask); - break; - case PACKET_6BYTE_PACKET_NUMBER: - return writer->WriteUInt48(packet_number & k6ByteSequenceNumberMask); - break; - default: - DCHECK(false) << "packet_number_length: " << packet_number_length; - return false; + return writer->WriteBytesToUInt64(packet_number_length, packet_number); +} + +// static +bool QuicFramer::AppendStreamId(size_t stream_id_length, + QuicStreamId stream_id, + QuicDataWriter* writer) { + if (stream_id_length == 0 || stream_id_length > 4) { + QUIC_BUG << "Invalid stream_id_length: " << stream_id_length; + return false; } + return writer->WriteBytesToUInt64(stream_id_length, stream_id); +} + +// static +bool QuicFramer::AppendStreamOffset(size_t offset_length, + QuicStreamOffset offset, + QuicDataWriter* writer) { + if (offset_length == 1 || offset_length > 8) { + QUIC_BUG << "Invalid stream_offset_length: " << offset_length; + return false; + } + + return writer->WriteBytesToUInt64(offset_length, offset); } // static @@ -1790,18 +1798,20 @@ QuicPacketNumberLength length_length, QuicPacketNumber length, QuicDataWriter* writer) { - return AppendPacketSequenceNumber(PACKET_1BYTE_PACKET_NUMBER, gap, writer) && - AppendPacketSequenceNumber(length_length, length, writer); + return writer->WriteUInt8(gap) && + AppendPacketNumber(length_length, length, writer); } bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame, bool no_stream_frame_length, QuicDataWriter* writer) { - if (!writer->WriteBytes(&frame.stream_id, GetStreamIdSize(frame.stream_id))) { + if (!AppendStreamId(GetStreamIdSize(frame.stream_id), frame.stream_id, + writer)) { QUIC_BUG << "Writing stream id size failed."; return false; } - if (!writer->WriteBytes(&frame.offset, GetStreamOffsetSize(frame.offset))) { + if (!AppendStreamOffset(GetStreamOffsetSize(frame.offset), frame.offset, + writer)) { QUIC_BUG << "Writing offset size failed."; return false; } @@ -1830,9 +1840,9 @@ const AckFrameInfo new_ack_info = GetAckFrameInfo(frame); QuicPacketNumber largest_acked = frame.largest_observed; QuicPacketNumberLength largest_acked_length = - GetMinSequenceNumberLength(largest_acked); + GetMinPacketNumberLength(largest_acked); QuicPacketNumberLength ack_block_length = - GetMinSequenceNumberLength(new_ack_info.max_block_length); + GetMinPacketNumberLength(new_ack_info.max_block_length); // Calculate available bytes for timestamps and ack blocks. int32_t available_timestamp_and_ack_block_bytes = writer->capacity() - writer->length() - ack_block_length - @@ -1849,11 +1859,11 @@ // Largest acked length. type_byte <<= kQuicSequenceNumberLengthShift; - type_byte |= GetSequenceNumberFlags(largest_acked_length); + type_byte |= GetPacketNumberFlags(largest_acked_length); // Ack block length. type_byte <<= kQuicSequenceNumberLengthShift; - type_byte |= GetSequenceNumberFlags(ack_block_length); + type_byte |= GetPacketNumberFlags(ack_block_length); type_byte |= kQuicFrameTypeAckMask; @@ -1862,8 +1872,7 @@ } // Largest acked. - if (!AppendPacketSequenceNumber(largest_acked_length, largest_acked, - writer)) { + if (!AppendPacketNumber(largest_acked_length, largest_acked, writer)) { return false; } @@ -1894,8 +1903,8 @@ } // First ack block length. - if (!AppendPacketSequenceNumber(ack_block_length, - new_ack_info.first_block_length, writer)) { + if (!AppendPacketNumber(ack_block_length, new_ack_info.first_block_length, + writer)) { return false; } @@ -2001,8 +2010,7 @@ return false; } - if (!writer->WriteUInt8(delta_from_largest_observed & - k1ByteSequenceNumberMask)) { + if (!writer->WriteUInt8(delta_from_largest_observed)) { return false; } @@ -2011,7 +2019,7 @@ uint32_t time_delta_us = static_cast<uint32_t>((it->second - creation_time_).ToMicroseconds() & (time_epoch_delta_us - 1)); - if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) { + if (!writer->WriteUInt32(time_delta_us)) { return false; } @@ -2025,8 +2033,7 @@ return false; } - if (!writer->WriteUInt8(delta_from_largest_observed & - k1ByteSequenceNumberMask)) { + if (!writer->WriteUInt8(delta_from_largest_observed)) { return false; } @@ -2057,8 +2064,8 @@ << " version:" << quic_version_; return false; } - if (!AppendPacketSequenceNumber(header.public_header.packet_number_length, - least_unacked_delta, writer)) { + if (!AppendPacketNumber(header.public_header.packet_number_length, + least_unacked_delta, writer)) { QUIC_BUG << " seq failed: " << header.public_header.packet_number_length; return false; } @@ -2161,4 +2168,8 @@ return false; } +Endianness QuicFramer::endianness() const { + return quic_version_ > QUIC_VERSION_38 ? NETWORK_BYTE_ORDER : HOST_BYTE_ORDER; +} + } // namespace net
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h index 6cb8522..f244191f 100644 --- a/net/quic/core/quic_framer.h +++ b/net/quic/core/quic_framer.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -312,7 +313,7 @@ const std::string& detailed_error() { return detailed_error_; } // The minimum packet number length required to represent |packet_number|. - static QuicPacketNumberLength GetMinSequenceNumberLength( + static QuicPacketNumberLength GetMinPacketNumberLength( QuicPacketNumber packet_number); void SetSupportedVersions(const QuicVersionVector& versions) { @@ -320,6 +321,9 @@ quic_version_ = versions[0]; } + // Returns byte order to read/write integers and floating numbers. + Endianness endianness() const; + void set_validate_flags(bool value) { validate_flags_ = value; } Perspective perspective() const { return perspective_; } @@ -364,10 +368,14 @@ bool ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header); - bool ProcessPacketSequenceNumber(QuicDataReader* reader, - QuicPacketNumberLength packet_number_length, - QuicPacketNumber base_packet_number, - QuicPacketNumber* packet_number); + // First processes possibly truncated packet number. Calculates the full + // packet number from the truncated one and the last seen packet number, and + // stores it to |packet_number|. + bool ProcessAndCalculatePacketNumber( + QuicDataReader* reader, + QuicPacketNumberLength packet_number_length, + QuicPacketNumber base_packet_number, + QuicPacketNumber* packet_number); bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header); bool ProcessStreamFrame(QuicDataReader* reader, uint8_t frame_type, @@ -425,10 +433,15 @@ bool last_frame_in_packet, QuicPacketNumberLength packet_number_length); - static bool AppendPacketSequenceNumber( - QuicPacketNumberLength packet_number_length, - QuicPacketNumber packet_number, - QuicDataWriter* writer); + static bool AppendPacketNumber(QuicPacketNumberLength packet_number_length, + QuicPacketNumber packet_number, + QuicDataWriter* writer); + static bool AppendStreamId(size_t stream_id_length, + QuicStreamId stream_id, + QuicDataWriter* writer); + static bool AppendStreamOffset(size_t offset_length, + QuicStreamOffset offset, + QuicDataWriter* writer); // Appends a single ACK block to |writer| and returns true if the block was // successfully appended. @@ -437,7 +450,7 @@ QuicPacketNumber length, QuicDataWriter* writer); - static uint8_t GetSequenceNumberFlags( + static uint8_t GetPacketNumberFlags( QuicPacketNumberLength packet_number_length); static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame);
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc index a39a272..b6a6fe72 100644 --- a/net/quic/core/quic_framer_test.cc +++ b/net/quic/core/quic_framer_test.cc
@@ -31,6 +31,7 @@ namespace net { namespace test { +namespace { const QuicPacketNumber kEpoch = UINT64_C(1) << 48; const QuicPacketNumber kMask = kEpoch - 1; @@ -446,6 +447,26 @@ test::TestQuicVisitor visitor_; }; +// Helper function to get index of packets in hex format. +// For each packet in hex format, integers and floating numbers are in big +// endian for v38 and up, and connection ID is in big endian according to +// perspective and flags. +// There are 4 combinations: +// 0 : little endian connection ID, little endian integers/floating numbers. +// 1 : big endian connection ID, little endian integers/floating numbers. +// 2 : little endian connection ID, big endian integers/floating numbers. +// 3 : big endian connection ID, big endian integers/floating numbers. +size_t GetPacketIndex(QuicVersion version, Perspective perspective) { + size_t index = 0; + if (QuicUtils::IsConnectionIdWireFormatBigEndian(perspective)) { + index = 1; + } + if (version > QUIC_VERSION_38) { + index += 2; + } + return index; +} + // Run all framer tests with all supported versions of QUIC. INSTANTIATE_TEST_CASE_P(QuicFramerTests, QuicFramerTest, @@ -627,17 +648,31 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -661,11 +696,8 @@ } else { expected_error = "Unable to read packet number."; } - CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - i, expected_error, QUIC_INVALID_PACKET_HEADER); + CheckProcessingFails(packets[index], i, expected_error, + QUIC_INVALID_PACKET_HEADER); } } @@ -681,9 +713,20 @@ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, }; + + unsigned char packet39[] = { + // public flags (0 byte connection_id) + 0x30, + // connection_id + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + QuicEncryptedPacket encrypted( + AsChars(framer_.version() > QUIC_VERSION_38 ? packet39 : packet), + arraysize(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -708,7 +751,9 @@ } else { expected_error = "Unable to read packet number."; } - CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); + CheckProcessingFails( + framer_.version() > QUIC_VERSION_38 ? packet39 : packet, i, + expected_error, QUIC_INVALID_PACKET_HEADER); } } @@ -735,17 +780,35 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, }; + + unsigned char packet39[] = { + // public flags (version) + 0x39, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + }; + + unsigned char packet_cid_be39[] = { + // public flags (version) + 0x39, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -772,11 +835,8 @@ } else { expected_error = "Unable to read packet number."; } - CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - i, expected_error, QUIC_INVALID_PACKET_HEADER); + CheckProcessingFails(packets[index], i, expected_error, + QUIC_INVALID_PACKET_HEADER); } } @@ -801,17 +861,31 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id and 4 byte packet number) + 0x28, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x56, 0x78, 0x9A, 0xBC, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id and 4 byte packet number) + 0x28, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x56, 0x78, 0x9A, 0xBC, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -835,11 +909,8 @@ } else { expected_error = "Unable to read packet number."; } - CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - i, expected_error, QUIC_INVALID_PACKET_HEADER); + CheckProcessingFails(packets[index], i, expected_error, + QUIC_INVALID_PACKET_HEADER); } } @@ -864,17 +935,31 @@ // packet number 0xBC, 0x9A, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id and 2 byte packet number) + 0x18, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x9A, 0xBC, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id and 2 byte packet number) + 0x18, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x9A, 0xBC, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -900,11 +985,8 @@ } else { expected_error = "Unable to read packet number."; } - CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - i, expected_error, QUIC_INVALID_PACKET_HEADER); + CheckProcessingFails(packets[index], i, expected_error, + QUIC_INVALID_PACKET_HEADER); } } @@ -1070,17 +1152,50 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; - // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char packet39[] = { + // public flags: includes nonce flag + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x3C : 0x7C), + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // nonce + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (padding) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + unsigned char packet_cid_be39[] = { + // public flags: includes nonce flag + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x3C : 0x7C), + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // nonce + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (padding) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); ASSERT_TRUE(visitor_.public_header_->nonce != nullptr); @@ -1127,16 +1242,47 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id, version flag and an unknown flag) + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x39 : 0x79), + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // version tag + 'Q', '0', '0', '0', + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id, version flag and an unknown flag) + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_multipath_bit ? 0x39 : 0x79), + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + 'Q', '0', '0', '0', + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -1296,21 +1442,74 @@ // paddings 0x00, 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // paddings + 0x00, 0x00, + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // paddings + 0x00, 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // paddings + 0x00, 0x00, + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // paddings + 0x00, 0x00, + }; // clang-format on if (framer_.version() <= QUIC_VERSION_37) { return; } - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -1378,17 +1577,61 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; - // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1404,11 +1647,8 @@ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); // Now test framing boundaries. - CheckStreamFrameBoundaries( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - kQuicMaxStreamIdSize, !kIncludeVersion); + CheckStreamFrameBoundaries(packets[index], kQuicMaxStreamIdSize, + !kIncludeVersion); } TEST_P(QuicFramerTest, MissingDiversificationNonce) { @@ -1467,17 +1707,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); } @@ -1532,17 +1817,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFE, + // stream id + 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFE, + // stream id + 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1560,11 +1890,7 @@ // Now test framing boundaries. const size_t stream_id_size = 3; - CheckStreamFrameBoundaries( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - stream_id_size, !kIncludeVersion); + CheckStreamFrameBoundaries(packets[index], stream_id_size, !kIncludeVersion); } TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { @@ -1617,17 +1943,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFD, + // stream id + 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFD, + // stream id + 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1645,11 +2016,7 @@ // Now test framing boundaries. const size_t stream_id_size = 2; - CheckStreamFrameBoundaries( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - stream_id_size, !kIncludeVersion); + CheckStreamFrameBoundaries(packets[index], stream_id_size, !kIncludeVersion); } TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { @@ -1702,17 +2069,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFC, + // stream id + 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFC, + // stream id + 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1730,11 +2142,7 @@ // Now test framing boundaries. const size_t stream_id_size = 1; - CheckStreamFrameBoundaries( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - stream_id_size, !kIncludeVersion); + CheckStreamFrameBoundaries(packets[index], stream_id_size, !kIncludeVersion); } TEST_P(QuicFramerTest, StreamFrameWithVersion) { @@ -1791,17 +2199,66 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (version, 8 byte connection_id) + 0x39, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (version, 8 byte connection_id) + 0x39, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1819,11 +2276,8 @@ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); // Now test framing boundaries. - CheckStreamFrameBoundaries( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - kQuicMaxStreamIdSize, kIncludeVersion); + CheckStreamFrameBoundaries(packets[index], kQuicMaxStreamIdSize, + kIncludeVersion); } TEST_P(QuicFramerTest, RejectPacket) { @@ -1878,17 +2332,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1978,17 +2477,55 @@ // num timestamps. 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (one ack block, 2 byte largest observed, 2 byte block length) + 0x45, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x12, 0x34, + // num timestamps. + 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (one ack block, 2 byte largest observed, 2 byte block length) + 0x45, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x12, 0x34, + // num timestamps. + 0x00, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2024,9 +2561,7 @@ expected_error = "Unable to read num received packets."; } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2129,17 +2664,107 @@ // Delta time. 0x10, 0x32, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (more than one ack block, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0x04, + // first ack block length. + 0x00, 0x01, + // gap to next block. + 0x01, + // ack block length. + 0x0e, 0xaf, + // gap to next block. + 0xff, + // ack block length. + 0x00, 0x00, + // gap to next block. + 0x91, + // ack block length. + 0x01, 0xea, + // gap to next block. + 0x05, + // ack block length. + 0x00, 0x04, + // Number of timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x76, 0x54, 0x32, 0x10, + // Delta from largest observed. + 0x02, + // Delta time. + 0x32, 0x10, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (more than one ack block, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0x04, + // first ack block length. + 0x00, 0x01, + // gap to next block. + 0x01, + // ack block length. + 0x0e, 0xaf, + // gap to next block. + 0xff, + // ack block length. + 0x00, 0x00, + // gap to next block. + 0x91, + // ack block length. + 0x01, 0xea, + // gap to next block. + 0x05, + // ack block length. + 0x00, 0x04, + // Number of timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x76, 0x54, 0x32, 0x10, + // Delta from largest observed. + 0x02, + // Delta time. + 0x32, 0x10, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2226,9 +2851,7 @@ } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2268,17 +2891,44 @@ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xA8, + // frame type (stop waiting frame) + 0x06, + // least packet number awaiting an ack, delta from packet number. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xA8, + // frame type (stop waiting frame) + 0x06, + // least packet number awaiting an ack, delta from packet number. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2296,9 +2946,7 @@ string expected_error; expected_error = "Unable to read least unacked delta."; CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2352,17 +3000,58 @@ // error code 0x01, 0x00, 0x00, 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (rst stream frame) + 0x01, + // stream id + 0x01, 0x02, 0x03, 0x04, + + // sent byte offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + + // error code + 0x00, 0x00, 0x00, 0x01, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (rst stream frame) + 0x01, + // stream id + 0x01, 0x02, 0x03, 0x04, + + // sent byte offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + + // error code + 0x00, 0x00, 0x00, 0x01, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2388,9 +3077,7 @@ expected_error = "Unable to read rst stream error code."; } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2446,17 +3133,60 @@ 'I', ' ', 'c', 'a', 'n', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (connection close frame) + 0x02, + // error code + 0x00, 0x00, 0x00, 0x11, + + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (connection close frame) + 0x02, + // error code + 0x00, 0x00, 0x00, 0x11, + + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2481,9 +3211,7 @@ expected_error = "Unable to read connection close error details."; } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2541,17 +3269,62 @@ 'I', ' ', 'c', 'a', 'n', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (go away frame) + 0x03, + // error code + 0x00, 0x00, 0x00, 0x09, + // stream id + 0x01, 0x02, 0x03, 0x04, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (go away frame) + 0x03, + // error code + 0x00, 0x00, 0x00, 0x09, + // stream id + 0x01, 0x02, 0x03, 0x04, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2577,9 +3350,7 @@ expected_error = "Unable to read goaway reason."; } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2625,17 +3396,50 @@ 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (window update frame) + 0x04, + // stream id + 0x01, 0x02, 0x03, 0x04, + // byte offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (window update frame) + 0x04, + // stream id + 0x01, 0x02, 0x03, 0x04, + // byte offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2656,9 +3460,7 @@ expected_error = "Unable to read window byte_offset."; } CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2698,17 +3500,44 @@ // stream id 0x04, 0x03, 0x02, 0x01, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (blocked frame) + 0x05, + // stream id + 0x01, 0x02, 0x03, 0x04, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (blocked frame) + 0x05, + // stream id + 0x01, 0x02, 0x03, 0x04, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2723,9 +3552,7 @@ ++i) { string expected_error = "Unable to read stream_id."; CheckProcessingFails( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, + packets[index], i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER), @@ -2761,17 +3588,40 @@ // frame type (ping frame) 0x07, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2855,7 +3705,6 @@ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); - EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number); EXPECT_EQ( IpAddressFamily::IP_UNSPEC, visitor_.public_reset_packet_->client_address.host().address_family()); @@ -2974,7 +3823,6 @@ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); - EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number); EXPECT_EQ( IpAddressFamily::IP_UNSPEC, visitor_.public_reset_packet_->client_address.host().address_family()); @@ -3176,7 +4024,6 @@ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); - EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number); EXPECT_EQ("4.31.198.44", visitor_.public_reset_packet_->client_address.host().ToString()); EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port()); @@ -3380,29 +4227,52 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet39[kMaxPacketSize] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + unsigned char packet_cid_be39[kMaxPacketSize] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + uint64_t header_size = GetPacketHeaderSize( framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER); - memset((QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet) + - header_size + 1, - 0x00, kMaxPacketSize - header_size - 1); + memset((packets[index]) + header_size + 1, 0x00, + kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { @@ -3478,20 +4348,74 @@ // paddings 0x00, 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // paddings + 0x00, 0x00, + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // paddings + 0x00, 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // paddings + 0x00, 0x00, + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // paddings + 0x00, 0x00, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { @@ -3531,29 +4455,50 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet39[kMaxPacketSize] = { + // public flags (8 byte connection_id and 4 byte packet number) + 0x28, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x56, 0x78, 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + unsigned char packet_cid_be39[kMaxPacketSize] = { + // public flags (8 byte connection_id and 4 byte packet number) + 0x28, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x56, 0x78, 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + uint64_t header_size = GetPacketHeaderSize( framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); - memset((QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet) + - header_size + 1, - 0x00, kMaxPacketSize - header_size - 1); + memset((packets[index]) + header_size + 1, 0x00, + kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { @@ -3593,29 +4538,50 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet39[kMaxPacketSize] = { + // public flags (8 byte connection_id and 2 byte packet number) + 0x18, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + unsigned char packet_cid_be39[kMaxPacketSize] = { + // public flags (8 byte connection_id and 2 byte packet number) + 0x18, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x9A, 0xBC, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + uint64_t header_size = GetPacketHeaderSize( framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER); - memset((QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet) + - header_size + 1, - 0x00, kMaxPacketSize - header_size - 1); + memset((packets[index]) + header_size + 1, 0x00, + kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { @@ -3737,20 +4703,62 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin and no length) + 0xDF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin and no length) + 0xDF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { @@ -3806,21 +4814,60 @@ // data 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (version, 8 byte connection_id) + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2 ? 0x39 : 0x3D), + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (stream frame with fin and no length) + 0xDF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, + // data + 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (version, 8 byte connection_id) + static_cast<unsigned char>( + FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2 ? 0x39 : 0x3D), + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (stream frame with fin and no length) + 0xDF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, + // data + 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { @@ -3916,20 +4963,59 @@ // num timestamps. 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (no ack blocks, 2 byte largest observed, 2 byte block length) + 0x45, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x12, 0x34, + // num timestamps. + 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (no ack blocks, 2 byte largest observed, 2 byte block length) + 0x45, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x12, 0x34, + // num timestamps. + 0x00, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { @@ -4028,20 +5114,95 @@ // num timestamps. 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (has ack blocks, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0x04, + // first ack block length. + 0x00, 0x01, + // gap to next block. + 0x01, + // ack block length. + 0x0e, 0xaf, + // gap to next block. + 0xff, + // ack block length. + 0x00, 0x00, + // gap to next block. + 0x91, + // ack block length. + 0x01, 0xea, + // gap to next block. + 0x05, + // ack block length. + 0x00, 0x04, + // num timestamps. + 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (ack frame) + // (has ack blocks, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0x04, + // first ack block length. + 0x00, 0x01, + // gap to next block. + 0x01, + // ack block length. + 0x0e, 0xaf, + // gap to next block. + 0xff, + // ack block length. + 0x00, 0x00, + // gap to next block. + 0x91, + // ack block length. + 0x01, 0xea, + // gap to next block. + 0x05, + // ack block length. + 0x00, 0x04, + // num timestamps. + 0x00, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { @@ -4249,20 +5410,203 @@ // num timestamps. 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + // frame type (ack frame) + // (has ack blocks, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0xff, + // first ack block length. + 0x0f, 0xdd, + // 255 = 4 * 63 + 3 + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + // num timestamps. + 0x00, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + // frame type (ack frame) + // (has ack blocks, 2 byte largest observed, 2 byte block length) + 0x65, + // largest acked + 0x12, 0x34, + // Zero delta time. + 0x00, 0x00, + // num ack blocks ranges. + 0xff, + // first ack block length. + 0x0f, 0xdd, + // 255 = 4 * 63 + 3 + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + // num timestamps. + 0x00, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { @@ -4308,20 +5652,48 @@ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (stop waiting frame) + 0x06, + // least packet number awaiting an ack, delta from packet number. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + + // frame type (stop waiting frame) + 0x06, + // least packet number awaiting an ack, delta from packet number. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { @@ -4377,22 +5749,60 @@ // error code 0x08, 0x07, 0x06, 0x05, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (rst stream frame) + 0x01, + // stream id + 0x01, 0x02, 0x03, 0x04, + // sent byte offset + 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, + // error code + 0x05, 0x06, 0x07, 0x08, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (rst stream frame) + 0x01, + // stream id + 0x01, 0x02, 0x03, 0x04, + // sent byte offset + 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, + // error code + 0x05, 0x06, 0x07, 0x08, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + QuicFrames frames = {QuicFrame(&rst_frame)}; std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildCloseFramePacket) { @@ -4453,20 +5863,62 @@ 'I', ' ', 'c', 'a', 'n', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (connection close frame) + 0x02, + // error code + 0x05, 0x06, 0x07, 0x08, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (connection close frame) + 0x02, + // error code + 0x05, 0x06, 0x07, 0x08, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildGoAwayPacket) { @@ -4532,20 +5984,66 @@ 'I', ' ', 'c', 'a', 'n', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (go away frame) + 0x03, + // error code + 0x05, 0x06, 0x07, 0x08, + // stream id + 0x01, 0x02, 0x03, 0x04, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (go away frame) + 0x03, + // error code + 0x05, 0x06, 0x07, 0x08, + // stream id + 0x01, 0x02, 0x03, 0x04, + // error details length + 0x00, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { @@ -4598,20 +6096,54 @@ 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (window update frame) + 0x04, + // stream id + 0x01, 0x02, 0x03, 0x04, + // byte offset + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (window update frame) + 0x04, + // stream id + 0x01, 0x02, 0x03, 0x04, + // byte offset + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildBlockedPacket) { @@ -4657,20 +6189,48 @@ // stream id 0x04, 0x03, 0x02, 0x01, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (blocked frame) + 0x05, + // stream id + 0x01, 0x02, 0x03, 0x04, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (blocked frame) + 0x05, + // stream id + 0x01, 0x02, 0x03, 0x04, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } TEST_P(QuicFramerTest, BuildPingPacket) { @@ -4709,20 +6269,44 @@ // frame type (ping frame) 0x07, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); } // Test that the MTU discovery packet is serialized correctly as a PING packet. @@ -4762,11 +6346,159 @@ // frame type (ping frame) 0x07, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (ping frame) + 0x07, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packets[index]), + arraysize(packet)); +} + +TEST_P(QuicFramerTest, BuildPublicResetPacketOld) { + FLAGS_quic_reloadable_flag_quic_use_old_public_reset_packets = true; + QuicPublicResetPacket reset_packet; + reset_packet.public_header.connection_id = kConnectionId; + reset_packet.public_header.reset_flag = true; + reset_packet.public_header.version_flag = false; + reset_packet.nonce_proof = kNonceProof; + + // clang-format off + unsigned char packet[] = { + // public flags (public reset, 8 byte ConnectionId) + 0x0E, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // message tag (kPRST) + 'P', 'R', 'S', 'T', + // num_entries (1) + padding + 0x01, 0x00, 0x00, 0x00, + // tag kRNON + 'R', 'N', 'O', 'N', + // end offset 8 + 0x08, 0x00, 0x00, 0x00, + // nonce proof + 0x89, 0x67, 0x45, 0x23, + 0x01, 0xEF, 0xCD, 0xAB, + }; + + unsigned char packet_cid_be[] = { + // public flags (public reset, 8 byte ConnectionId) + 0x0E, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // message tag (kPRST) + 'P', 'R', 'S', 'T', + // num_entries (1) + padding + 0x01, 0x00, 0x00, 0x00, + // tag kRNON + 'R', 'N', 'O', 'N', + // end offset 8 + 0x08, 0x00, 0x00, 0x00, + // nonce proof + 0x89, 0x67, 0x45, 0x23, + 0x01, 0xEF, 0xCD, 0xAB, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> data( + framer_.BuildPublicResetPacket(reset_packet)); + ASSERT_TRUE(data != nullptr); + test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), + AsChars( + QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) + ? packet_cid_be + : packet), + QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) + ? arraysize(packet_cid_be) + : arraysize(packet)); +} + +TEST_P(QuicFramerTest, BuildPublicResetPacket) { + FLAGS_quic_reloadable_flag_quic_use_old_public_reset_packets = false; + QuicPublicResetPacket reset_packet; + reset_packet.public_header.connection_id = kConnectionId; + reset_packet.public_header.reset_flag = true; + reset_packet.public_header.version_flag = false; + reset_packet.nonce_proof = kNonceProof; + + // clang-format off + unsigned char packet[] = { + // public flags (public reset, 8 byte ConnectionId) + 0x0A, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // message tag (kPRST) + 'P', 'R', 'S', 'T', + // num_entries (1) + padding + 0x01, 0x00, 0x00, 0x00, + // tag kRNON + 'R', 'N', 'O', 'N', + // end offset 8 + 0x08, 0x00, 0x00, 0x00, + // nonce proof + 0x89, 0x67, 0x45, 0x23, + 0x01, 0xEF, 0xCD, 0xAB, + }; + + unsigned char packet_cid_be[] = { + // public flags (public reset, 8 byte ConnectionId) + 0x0A, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, + 0x76, 0x54, 0x32, 0x10, + // message tag (kPRST) + 'P', 'R', 'S', 'T', + // num_entries (1) + padding + 0x01, 0x00, 0x00, 0x00, + // tag kRNON + 'R', 'N', 'O', 'N', + // end offset 8 + 0x08, 0x00, 0x00, 0x00, + // nonce proof + 0x89, 0x67, 0x45, 0x23, + 0x01, 0xEF, 0xCD, 0xAB, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> data( + framer_.BuildPublicResetPacket(reset_packet)); + ASSERT_TRUE(data != nullptr); + test::CompareCharArraysWithHexError( "constructed packet", data->data(), data->length(), AsChars( @@ -4778,337 +6510,18 @@ : arraysize(packet)); } -TEST_P(QuicFramerTest, BuildPublicResetPacketOld) { - FLAGS_quic_reloadable_flag_quic_use_old_public_reset_packets = true; - QuicPublicResetPacket reset_packet; - reset_packet.public_header.connection_id = kConnectionId; - reset_packet.public_header.reset_flag = true; - reset_packet.public_header.version_flag = false; - reset_packet.rejected_packet_number = kPacketNumber; - reset_packet.nonce_proof = kNonceProof; - - // clang-format off - unsigned char packet[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0E, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (2) + padding - 0x02, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - }; - - unsigned char packet_cid_be[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0E, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (2) + padding - 0x02, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - }; - - unsigned char packet_no_rejected_packet_number[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0E, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (1) + padding - 0x01, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - }; - - unsigned char packet_no_rejected_packet_number_cid_be[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0E, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (1) + padding - 0x01, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - }; - // clang-format on - - std::unique_ptr<QuicEncryptedPacket> data( - framer_.BuildPublicResetPacket(reset_packet)); - ASSERT_TRUE(data != nullptr); - if (FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset) { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_no_rejected_packet_number_cid_be - : packet_no_rejected_packet_number), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_no_rejected_packet_number_cid_be) - : arraysize(packet_no_rejected_packet_number)); - } else { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); - } -} - -TEST_P(QuicFramerTest, BuildPublicResetPacket) { - FLAGS_quic_reloadable_flag_quic_use_old_public_reset_packets = false; - QuicPublicResetPacket reset_packet; - reset_packet.public_header.connection_id = kConnectionId; - reset_packet.public_header.reset_flag = true; - reset_packet.public_header.version_flag = false; - reset_packet.rejected_packet_number = kPacketNumber; - reset_packet.nonce_proof = kNonceProof; - - // clang-format off - unsigned char packet[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (2) + padding - 0x02, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - }; - - unsigned char packet_cid_be[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (2) + padding - 0x02, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - }; - - unsigned char packet_no_rejected_packet_number[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (1) + padding - 0x01, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - }; - - unsigned char packet_no_rejected_packet_number_cid_be[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (1) + padding - 0x01, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - }; - // clang-format on - - std::unique_ptr<QuicEncryptedPacket> data( - framer_.BuildPublicResetPacket(reset_packet)); - ASSERT_TRUE(data != nullptr); - - if (FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset) { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_no_rejected_packet_number_cid_be - : packet_no_rejected_packet_number), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_no_rejected_packet_number_cid_be) - : arraysize(packet_no_rejected_packet_number)); - } else { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); - } -} - TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) { FLAGS_quic_reloadable_flag_quic_use_old_public_reset_packets = false; QuicPublicResetPacket reset_packet; reset_packet.public_header.connection_id = kConnectionId; reset_packet.public_header.reset_flag = true; reset_packet.public_header.version_flag = false; - reset_packet.rejected_packet_number = kPacketNumber; reset_packet.nonce_proof = kNonceProof; reset_packet.client_address = QuicSocketAddress(QuicIpAddress::Loopback4(), 0x1234); // clang-format off unsigned char packet[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (3) + padding - 0x03, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // tag kCADR - 'C', 'A', 'D', 'R', - // end offset 24 - 0x18, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - // client address - 0x02, 0x00, - 0x7F, 0x00, 0x00, 0x01, - 0x34, 0x12, - }; - - unsigned char packet_cid_be[] = { - // public flags (public reset, 8 byte ConnectionId) - 0x0A, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // message tag (kPRST) - 'P', 'R', 'S', 'T', - // num_entries (3) + padding - 0x03, 0x00, 0x00, 0x00, - // tag kRNON - 'R', 'N', 'O', 'N', - // end offset 8 - 0x08, 0x00, 0x00, 0x00, - // tag kRSEQ - 'R', 'S', 'E', 'Q', - // end offset 16 - 0x10, 0x00, 0x00, 0x00, - // tag kCADR - 'C', 'A', 'D', 'R', - // end offset 24 - 0x18, 0x00, 0x00, 0x00, - // nonce proof - 0x89, 0x67, 0x45, 0x23, - 0x01, 0xEF, 0xCD, 0xAB, - // rejected packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, 0x00, 0x00, - // client address - 0x02, 0x00, - 0x7F, 0x00, 0x00, 0x01, - 0x34, 0x12, - }; - - unsigned char packet_no_rejected_packet_number[] = { // public flags (public reset, 8 byte ConnectionId) 0x0A, // connection_id @@ -5135,11 +6548,12 @@ 0x34, 0x12, }; - unsigned char packet_no_rejected_packet_number_cid_be[] = { + unsigned char packet_cid_be[] = { // public flags (public reset, 8 byte ConnectionId) 0x0A, // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0xFE, 0xDC, 0xBA, 0x98, + 0x76, 0x54, 0x32, 0x10, // message tag (kPRST) 'P', 'R', 'S', 'T', // num_entries (2) + padding @@ -5166,29 +6580,16 @@ framer_.BuildPublicResetPacket(reset_packet)); ASSERT_TRUE(data != nullptr); - if (FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset) { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_no_rejected_packet_number_cid_be - : packet_no_rejected_packet_number), + test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), + AsChars( + QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) + ? packet_cid_be + : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_no_rejected_packet_number_cid_be) - : arraysize(packet_no_rejected_packet_number)); - } else { - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); - } + QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) + ? arraysize(packet_cid_be) + : arraysize(packet)); } TEST_P(QuicFramerTest, EncryptPacket) { @@ -5226,17 +6627,46 @@ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // redundancy + 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // redundancy + 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + AsChars(packets[index]), arraysize(packet), false, + PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( @@ -5285,17 +6715,51 @@ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', }; + + unsigned char packet39[] = { + // public flags (version, 8 byte connection_id) + 0x39, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // version tag + 'Q', '.', '1', '0', + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // redundancy + 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', + }; + + unsigned char packet_cid_be39[] = { + // public flags (version, 8 byte connection_id) + 0x39, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + 'Q', '.', '1', '0', + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // redundancy + 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, + AsChars(packets[index]), arraysize(packet), false, + PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( @@ -5485,8 +6949,88 @@ 0xBE, 0x9A, 0x78, 0x56, 0x34, 0x12, }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + + // frame type (ack frame) + 0x40, + // least packet number awaiting an ack + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xA0, + // largest observed packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBF, + // num missing packets + 0x01, + // missing packet + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBE, + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x38, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + + // frame type (ack frame) + 0x40, + // least packet number awaiting an ack + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xA0, + // largest observed packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBF, + // num missing packets + 0x01, + // missing packet + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBE, + }; // clang-format on + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + MockFramerVisitor visitor; framer_.set_visitor(&visitor); EXPECT_CALL(visitor, OnPacket()); @@ -5498,15 +7042,8 @@ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true)); EXPECT_CALL(visitor, OnDecryptedPacket(_)); - QuicEncryptedPacket encrypted( - AsChars( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet), - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet), - false); + QuicEncryptedPacket encrypted(AsChars(packets[index]), arraysize(packet), + false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); } @@ -5675,16 +7212,67 @@ 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + // private flags + 0x00, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + unsigned char packet_cid_be39[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, + // private flags + 0x00, + + // frame type (stream frame with fin) + 0xFF, + // stream id + 0x01, 0x02, 0x03, 0x04, + // offset + 0xBA, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + 0x00, 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; // clang-format on - QuicFramerFuzzFunc( - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? packet_cid_be - : packet, - QuicUtils::IsConnectionIdWireFormatBigEndian(framer_.perspective()) - ? arraysize(packet_cid_be) - : arraysize(packet)); + unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); + + QuicFramerFuzzFunc(packets[index], arraysize(packet)); } +} // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc index 6ee4217..0d2e293 100644 --- a/net/quic/core/quic_packet_creator.cc +++ b/net/quic/core/quic_packet_creator.cc
@@ -115,7 +115,7 @@ packet_.packet_number + 1 - least_packet_awaited_by_peer; const uint64_t delta = std::max(current_delta, max_packets_in_flight); packet_.packet_number_length = - QuicFramer::GetMinSequenceNumberLength(delta * 4); + QuicFramer::GetMinPacketNumberLength(delta * 4); } bool QuicPacketCreator::ConsumeData(QuicStreamId id, @@ -367,7 +367,7 @@ FillPacketHeader(&header); QUIC_CACHELINE_ALIGNED char encrypted_buffer[kMaxPacketSize]; QuicDataWriter writer(arraysize(encrypted_buffer), encrypted_buffer, - framer_->perspective()); + framer_->perspective(), framer_->endianness()); if (!framer_->AppendPacketHeader(header, &writer)) { QUIC_BUG << "AppendPacketHeader failed"; return;
diff --git a/net/quic/core/quic_packet_generator.cc b/net/quic/core/quic_packet_generator.cc index dc68d253..7487cde 100644 --- a/net/quic/core/quic_packet_generator.cc +++ b/net/quic/core/quic_packet_generator.cc
@@ -348,4 +348,9 @@ } } +bool QuicPacketGenerator::HasRetransmittableFrames() const { + return !queued_control_frames_.empty() || + packet_creator_.HasPendingRetransmittableFrames(); +} + } // namespace net
diff --git a/net/quic/core/quic_packet_generator.h b/net/quic/core/quic_packet_generator.h index bd4604c..43bffc1 100644 --- a/net/quic/core/quic_packet_generator.h +++ b/net/quic/core/quic_packet_generator.h
@@ -162,6 +162,10 @@ // Sets the encrypter to use for the encryption level. void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + // Returns true if there are control frames or current constructed packet has + // pending retransmittable frames. + bool HasRetransmittableFrames() const; + // Sets the encryption level that will be applied to new packets. void set_encryption_level(EncryptionLevel level);
diff --git a/net/quic/core/quic_packet_generator_test.cc b/net/quic/core/quic_packet_generator_test.cc index 514d6df4..c37cfd3 100644 --- a/net/quic/core/quic_packet_generator_test.cc +++ b/net/quic/core/quic_packet_generator_test.cc
@@ -241,6 +241,7 @@ generator_.SetShouldSendAck(false); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) { @@ -256,6 +257,7 @@ generator_.SetShouldSendAck(false); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) { @@ -268,6 +270,7 @@ generator_.SetShouldSendAck(false); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_ack_frames = 1; @@ -299,6 +302,7 @@ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { @@ -306,6 +310,7 @@ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { @@ -314,6 +319,7 @@ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { @@ -322,13 +328,16 @@ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); generator_.FinishBatchOperations(); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); generator_.FlushAllQueuedFrames(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_rst_stream_frames = 1; @@ -343,6 +352,7 @@ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_rst_stream_frames = 1; @@ -357,6 +367,7 @@ EXPECT_EQ(0u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { @@ -368,6 +379,7 @@ EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { @@ -380,6 +392,7 @@ EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_stream_frames = 1; @@ -399,6 +412,7 @@ kCryptoStreamId, MakeIOVectorFromStringPiece("foo"), 0, NO_FIN, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_stream_frames = 1; @@ -429,6 +443,7 @@ EXPECT_EQ(4u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { @@ -442,12 +457,14 @@ EXPECT_EQ(4u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); // Now both frames will be flushed out. EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); generator_.FinishBatchOperations(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_stream_frames = 2; @@ -484,6 +501,7 @@ EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); // This frame will not fit with the existing frame, causing the queued frame // to be serialized, and it will be added to a new open packet. @@ -492,9 +510,11 @@ EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); creator_->Flush(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_stream_frames = 1; @@ -514,6 +534,7 @@ EXPECT_EQ(10000u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_stream_frames = 1; @@ -526,6 +547,7 @@ generator_.SetShouldSendAck(false); generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); delegate_.SetCanWriteAnything(); @@ -545,6 +567,7 @@ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); generator_.FinishBatchOperations(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; contents.num_ack_frames = 1; @@ -560,6 +583,7 @@ generator_.SetShouldSendAck(false); generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); delegate_.SetCanWriteAnything(); @@ -588,6 +612,7 @@ generator_.FinishBatchOperations(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // The first packet should have the queued data and part of the stream data. PacketContents contents; @@ -634,6 +659,7 @@ EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // We expect three packets, and first two of them have to be of packet_len // size. We check multiple packets (instead of just one) because we want to @@ -668,6 +694,7 @@ EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // Make sure we already have two packets. ASSERT_EQ(2u, packets_.size()); @@ -682,6 +709,7 @@ EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // We expect first data chunk to get fragmented, but the second one to fit // into a single packet. @@ -710,6 +738,7 @@ EXPECT_EQ(first_write_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); // Make sure we have no packets so far. ASSERT_EQ(0u, packets_.size()); @@ -724,6 +753,7 @@ generator_.SetMaxPacketLength(packet_len); EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // We expect to see exactly one packet serialized after that, because we send // a value somewhat exceeding new max packet size, and the tail data does not @@ -739,6 +769,7 @@ EXPECT_EQ(second_write_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); // We expect the first packet to be underfilled, and the second packet be up // to the new max packet size. @@ -763,6 +794,7 @@ generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); ASSERT_EQ(1u, packets_.size()); EXPECT_EQ(target_mtu, packets_[0].encrypted_length); @@ -797,10 +829,12 @@ EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // Send the MTU probe. generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); // Send data after the MTU probe. consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), @@ -808,6 +842,7 @@ EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); ASSERT_EQ(5u, packets_.size()); EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); @@ -843,6 +878,7 @@ EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_)); // Generator should have queued control frames, and creator should be empty. EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); EXPECT_FALSE(creator_->HasPendingFrames()); // This will not serialize any packets, because of the invalid frame. @@ -867,6 +903,7 @@ "Single frame cannot fit into a packet", _)); EXPECT_QUIC_BUG(generator_.AddControlFrame(QuicFrame(frame)), ""); EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); } TEST_F(QuicPacketGeneratorTest, RandomPaddingAfterFinSingleStreamSinglePacket) { @@ -896,6 +933,7 @@ generator_.FinishBatchOperations(); EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); EXPECT_EQ(1u, packets_.size()); PacketContents contents; @@ -933,6 +971,7 @@ generator_.FinishBatchOperations(); EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); EXPECT_LE(1u, packets_.size()); PacketContents contents; @@ -986,6 +1025,7 @@ EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); generator_.FinishBatchOperations(); EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); EXPECT_LE(2u, packets_.size()); PacketContents contents;
diff --git a/net/quic/core/quic_packets.cc b/net/quic/core/quic_packets.cc index 9075165..8788fbba 100644 --- a/net/quic/core/quic_packets.cc +++ b/net/quic/core/quic_packets.cc
@@ -70,12 +70,11 @@ QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default; -QuicPublicResetPacket::QuicPublicResetPacket() - : nonce_proof(0), rejected_packet_number(0) {} +QuicPublicResetPacket::QuicPublicResetPacket() : nonce_proof(0) {} QuicPublicResetPacket::QuicPublicResetPacket( const QuicPacketPublicHeader& header) - : public_header(header), nonce_proof(0), rejected_packet_number(0) {} + : public_header(header), nonce_proof(0) {} std::ostream& operator<<(std::ostream& os, const QuicPacketHeader& header) { os << "{ connection_id: " << header.public_header.connection_id
diff --git a/net/quic/core/quic_packets.h b/net/quic/core/quic_packets.h index 95bef7c..2707f69d 100644 --- a/net/quic/core/quic_packets.h +++ b/net/quic/core/quic_packets.h
@@ -96,9 +96,6 @@ QuicPacketPublicHeader public_header; QuicPublicResetNonceProof nonce_proof; - // TODO(fayang): remove rejected_packet_number when deprecating - // FLAGS_quic_reloadable_flag_quic_remove_packet_number_from_public_reset. - QuicPacketNumber rejected_packet_number; QuicSocketAddress client_address; };
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc index 9508fe39..9cda039 100644 --- a/net/quic/core/quic_session.cc +++ b/net/quic/core/quic_session.cc
@@ -77,7 +77,7 @@ // us this offset. if (frame.fin) { QuicStreamOffset final_byte_offset = frame.offset + frame.data_length; - UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset); + OnFinalByteOffsetReceived(stream_id, final_byte_offset); } return; } @@ -394,7 +394,7 @@ connection_->SetNumOpenStreams(dynamic_stream_map_.size()); } -void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset( +void QuicSession::OnFinalByteOffsetReceived( QuicStreamId stream_id, QuicStreamOffset final_byte_offset) { std::map<QuicStreamId, QuicStreamOffset>::iterator it = @@ -533,8 +533,7 @@ if (IsClosedStream(frame.stream_id)) { // The RST frame contains the final byte offset for the stream: we can now // update the connection level flow controller if needed. - UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id, - frame.byte_offset); + OnFinalByteOffsetReceived(frame.stream_id, frame.byte_offset); } } @@ -820,6 +819,10 @@ closed_streams_.clear(); } +void QuicSession::OnAckNeedsRetransmittableFrame() { + flow_controller_.SendWindowUpdate(); +} + size_t QuicSession::GetNumDynamicOutgoingStreams() const { DCHECK_GE(dynamic_stream_map_.size(), num_dynamic_incoming_streams_); return dynamic_stream_map_.size() - num_dynamic_incoming_streams_;
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h index 5fa9dcd..32f19589 100644 --- a/net/quic/core/quic_session.h +++ b/net/quic/core/quic_session.h
@@ -100,6 +100,8 @@ // Deletes streams that are safe to be deleted now that it's safe to do so (no // other operations are being done on the streams at this time). void PostProcessAfterData() override; + // Adds a connection level WINDOW_UPDATE frame. + void OnAckNeedsRetransmittableFrame() override; bool WillingAndAbleToWrite() const override; bool HasPendingHandshake() const override; bool HasOpenDynamicStreams() const override; @@ -292,11 +294,11 @@ // When a stream is closed locally, it may not yet know how many bytes the // peer sent on that stream. - // When this data arrives (via stream frame w. FIN, or RST) this method - // is called, and correctly updates the connection level flow controller. - void UpdateFlowControlOnFinalReceivedByteOffset( - QuicStreamId id, - QuicStreamOffset final_byte_offset); + // When this data arrives (via stream frame w. FIN, trailing headers, or RST) + // this method is called, and correctly updates the connection level flow + // controller. + virtual void OnFinalByteOffsetReceived(QuicStreamId id, + QuicStreamOffset final_byte_offset); // Return true if given stream is peer initiated. bool IsIncomingStream(QuicStreamId id) const;
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc index 77cd2cb..26d6d3c 100644 --- a/net/quic/core/quic_spdy_session.cc +++ b/net/quic/core/quic_spdy_session.cc
@@ -11,9 +11,11 @@ #include "net/quic/core/quic_headers_stream.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_str_cat.h" +#include "net/quic/platform/api/quic_text_utils.h" using std::string; @@ -393,7 +395,35 @@ size_t frame_len, const QuicHeaderList& header_list) { QuicSpdyStream* stream = GetSpdyDataStream(stream_id); - if (!stream) { + if (stream == nullptr) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_final_offset_from_trailers, 1, + 3); + if (FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_final_offset_from_trailers, 2, + 3); + // The stream no longer exists, but trailing headers may contain the final + // byte offset necessary for flow control and open stream accounting. + size_t final_byte_offset = 0; + for (const auto& header : header_list) { + const string& header_key = header.first; + const string& header_value = header.second; + if (header_key == kFinalOffsetHeaderKey) { + if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) { + connection()->CloseConnection( + QUIC_INVALID_HEADERS_STREAM_DATA, + "Trailers are malformed (no final offset)", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + DVLOG(1) << "Received final byte offset in trailers for stream " + << stream_id << ", which no longer exists."; + OnFinalByteOffsetReceived(stream_id, final_byte_offset); + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_final_offset_from_trailers, 3, 3); + } + } + } + // It's quite possible to receive headers after a stream has been reset. return; }
diff --git a/net/quic/core/quic_version_manager.cc b/net/quic/core/quic_version_manager.cc index 7652813..c67534c 100644 --- a/net/quic/core/quic_version_manager.cc +++ b/net/quic/core/quic_version_manager.cc
@@ -10,7 +10,7 @@ namespace net { QuicVersionManager::QuicVersionManager(QuicVersionVector supported_versions) - : enable_version_39_(FLAGS_quic_enable_version_39), + : enable_version_39_(FLAGS_quic_reloadable_flag_quic_enable_version_39), enable_version_38_(FLAGS_quic_reloadable_flag_quic_enable_version_38), allowed_supported_versions_(supported_versions), filtered_supported_versions_( @@ -24,9 +24,9 @@ } void QuicVersionManager::MaybeRefilterSupportedVersions() { - if (enable_version_39_ != FLAGS_quic_enable_version_39 || + if (enable_version_39_ != FLAGS_quic_reloadable_flag_quic_enable_version_39 || enable_version_38_ != FLAGS_quic_reloadable_flag_quic_enable_version_38) { - enable_version_39_ = FLAGS_quic_enable_version_39; + enable_version_39_ = FLAGS_quic_reloadable_flag_quic_enable_version_39; enable_version_38_ = FLAGS_quic_reloadable_flag_quic_enable_version_38; RefilterSupportedVersions(); }
diff --git a/net/quic/core/quic_version_manager.h b/net/quic/core/quic_version_manager.h index d658d8da..481cf6c 100644 --- a/net/quic/core/quic_version_manager.h +++ b/net/quic/core/quic_version_manager.h
@@ -31,7 +31,7 @@ } private: - // FLAGS_quic_enable_version_39 + // FLAGS_quic_reloadable_flag_quic_enable_version_39 bool enable_version_39_; // FLAGS_quic_reloadable_flag_quic_enable_version_38 bool enable_version_38_;
diff --git a/net/quic/core/quic_version_manager_test.cc b/net/quic/core/quic_version_manager_test.cc index b2ddbf5..0ba1f24 100644 --- a/net/quic/core/quic_version_manager_test.cc +++ b/net/quic/core/quic_version_manager_test.cc
@@ -16,6 +16,7 @@ TEST(QuicVersionManagerTest, QuicVersionManager) { QuicFlagSaver flags; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; FLAGS_quic_reloadable_flag_quic_enable_version_38 = false; QuicVersionManager manager(AllSupportedVersions()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), @@ -30,7 +31,7 @@ EXPECT_EQ(QUIC_VERSION_36, manager.GetSupportedVersions()[2]); EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[3]); - FLAGS_quic_enable_version_39 = true; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); ASSERT_EQ(5u, manager.GetSupportedVersions().size());
diff --git a/net/quic/core/quic_versions.cc b/net/quic/core/quic_versions.cc index 4a9583b2..a959726 100644 --- a/net/quic/core/quic_versions.cc +++ b/net/quic/core/quic_versions.cc
@@ -31,7 +31,7 @@ filtered_versions.clear(); // Guaranteed by spec not to change capacity. for (QuicVersion version : versions) { if (version == QUIC_VERSION_39) { - if (FLAGS_quic_enable_version_39 && + if (FLAGS_quic_reloadable_flag_quic_enable_version_39 && FLAGS_quic_reloadable_flag_quic_enable_version_38) { filtered_versions.push_back(version); }
diff --git a/net/quic/core/quic_versions.h b/net/quic/core/quic_versions.h index d228b41..7bd12ec 100644 --- a/net/quic/core/quic_versions.h +++ b/net/quic/core/quic_versions.h
@@ -29,8 +29,10 @@ QUIC_VERSION_37 = 37, // Add perspective into null encryption. QUIC_VERSION_38 = 38, // PADDING frame is a 1-byte frame with type 0x00. // Respect NSTP connection option. - QUIC_VERSION_39 = 39, // Experimental support for HTTP stream pairs - // and HPACK HoL avoidance. + QUIC_VERSION_39 = 39, // Integers and floating numbers are written in big + // endian. Dot not ack acks. Send a connection level + // WINDOW_UPDATE every 20 sent packets which do not + // contain retransmittable frames. // IMPORTANT: if you are adding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions
diff --git a/net/quic/core/quic_versions_test.cc b/net/quic/core/quic_versions_test.cc index 42493cf..83da0cc 100644 --- a/net/quic/core/quic_versions_test.cc +++ b/net/quic/core/quic_versions_test.cc
@@ -147,7 +147,7 @@ QUIC_VERSION_39}; FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_enable_version_39 = false; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions); ASSERT_EQ(4u, filtered_versions.size()); @@ -164,7 +164,7 @@ QUIC_VERSION_39}; FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_enable_version_39 = true; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions); ASSERT_EQ(all_versions, filtered_versions);
diff --git a/net/quic/core/spdy_utils.cc b/net/quic/core/spdy_utils.cc index cf16e34..5ad6a43 100644 --- a/net/quic/core/spdy_utils.cc +++ b/net/quic/core/spdy_utils.cc
@@ -32,24 +32,6 @@ } // static -bool SpdyUtils::ParseHeaders(const char* data, - uint32_t data_len, - int64_t* content_length, - SpdyHeaderBlock* headers) { - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - if (!framer.ParseHeaderBlockInBuffer(data, data_len, headers) || - headers->empty()) { - return false; // Headers were invalid. - } - - if (!QuicContainsKey(*headers, "content-length")) { - return true; - } - - return ExtractContentLengthFromHeaders(content_length, headers); -} - -// static bool SpdyUtils::ExtractContentLengthFromHeaders(int64_t* content_length, SpdyHeaderBlock* headers) { auto it = headers->find("content-length"); @@ -83,47 +65,6 @@ } } -// static -bool SpdyUtils::ParseTrailers(const char* data, - uint32_t data_len, - size_t* final_byte_offset, - SpdyHeaderBlock* trailers) { - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) || - trailers->empty()) { - QUIC_DVLOG(1) << "Request Trailers are invalid."; - return false; // Trailers were invalid. - } - - // Pull out the final offset pseudo header which indicates the number of - // response body bytes expected. - auto it = trailers->find(kFinalOffsetHeaderKey); - if (it == trailers->end() || - !QuicTextUtils::StringToSizeT(it->second, final_byte_offset)) { - QUIC_DLOG(ERROR) << "Required key '" << kFinalOffsetHeaderKey - << "' not present"; - return false; - } - // The final offset header is no longer needed. - trailers->erase(it->first); - - // Trailers must not have empty keys, and must not contain pseudo headers. - for (const auto& trailer : *trailers) { - QuicStringPiece key = trailer.first; - QuicStringPiece value = trailer.second; - if (QuicTextUtils::StartsWith(key, ":")) { - QUIC_DVLOG(1) << "Trailers must not contain pseudo-header: '" << key - << "','" << value << "'."; - return false; - } - - // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec. - } - - QUIC_DVLOG(1) << "Successfully parsed Trailers: " << trailers->DebugString(); - return true; -} - bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list, int64_t* content_length, SpdyHeaderBlock* headers) {
diff --git a/net/quic/core/spdy_utils.h b/net/quic/core/spdy_utils.h index 4f3f62b..724136af 100644 --- a/net/quic/core/spdy_utils.h +++ b/net/quic/core/spdy_utils.h
@@ -22,40 +22,18 @@ static std::string SerializeUncompressedHeaders( const SpdyHeaderBlock& headers); - // Parses |data| as a string containing serialized HTTP/2 HEADERS frame, - // populating |headers| with the key->value pairs found. - // |content_length| will be populated with the value of the content-length - // header if one or more are present. - // Returns true on success, false if parsing fails, or invalid keys are found. - static bool ParseHeaders(const char* data, - uint32_t data_len, - int64_t* content_length, - SpdyHeaderBlock* headers); - // Populate |content length| with the value of the content-length header. // Returns true on success, false if parsing fails or content-length header is // missing. static bool ExtractContentLengthFromHeaders(int64_t* content_length, SpdyHeaderBlock* headers); - // Parses |data| as a string containing serialized HTTP/2 HEADERS frame, - // populating |trailers| with the key->value pairs found. - // The final offset header will be excluded from |trailers|, and instead the - // value will be copied to |final_byte_offset|. - // Returns true on success, false if parsing fails, or invalid keys are found. - static bool ParseTrailers(const char* data, - uint32_t data_len, - size_t* final_byte_offset, - SpdyHeaderBlock* trailers); - - // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation - // to SpdyFramer::ParseHeaderBlockInBuffer and ParseHeaders, above. + // Copies a list of headers to a SpdyHeaderBlock. static bool CopyAndValidateHeaders(const QuicHeaderList& header_list, int64_t* content_length, SpdyHeaderBlock* headers); - // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation - // to SpdyFramer::ParseHeaderBlockInBuffer and ParseTrailers, above. + // Copies a list of headers to a SpdyHeaderBlock. static bool CopyAndValidateTrailers(const QuicHeaderList& header_list, size_t* final_byte_offset, SpdyHeaderBlock* trailers);
diff --git a/net/quic/core/spdy_utils_test.cc b/net/quic/core/spdy_utils_test.cc index 42200f27..d1149d4 100644 --- a/net/quic/core/spdy_utils_test.cc +++ b/net/quic/core/spdy_utils_test.cc
@@ -16,134 +16,6 @@ namespace net { namespace test { -TEST(SpdyUtilsTest, SerializeAndParseHeaders) { - // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then - // parses the serialized output and verifies that the end result is the same - // as the headers that the test started with. - - SpdyHeaderBlock input_headers; - input_headers[":pseudo1"] = "pseudo value1"; - input_headers[":pseudo2"] = "pseudo value2"; - input_headers["key1"] = "value1"; - const int64_t kContentLength = 1234; - input_headers["content-length"] = - QuicTextUtils::Uint64ToString(kContentLength); - input_headers["key2"] = "value2"; - - // Serialize the header block. - string serialized_headers = - SpdyUtils::SerializeUncompressedHeaders(input_headers); - - // Take the serialized header block, and parse back into SpdyHeaderBlock. - SpdyHeaderBlock output_headers; - int64_t content_length = -1; - ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(), - serialized_headers.size(), - &content_length, &output_headers)); - - // Should be back to the original headers. - EXPECT_EQ(content_length, kContentLength); - EXPECT_EQ(output_headers, input_headers); -} - -TEST(SpdyUtilsTest, SerializeAndParseHeadersLargeContentLength) { - // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then - // parses the serialized output and verifies that the end result is the same - // as the headers that the test started with. - - SpdyHeaderBlock input_headers; - input_headers[":pseudo1"] = "pseudo value1"; - input_headers[":pseudo2"] = "pseudo value2"; - input_headers["key1"] = "value1"; - const int64_t kContentLength = 12345678900; - input_headers["content-length"] = - QuicTextUtils::Uint64ToString(kContentLength); - input_headers["key2"] = "value2"; - - // Serialize the header block. - string serialized_headers = - SpdyUtils::SerializeUncompressedHeaders(input_headers); - - // Take the serialized header block, and parse back into SpdyHeaderBlock. - SpdyHeaderBlock output_headers; - int64_t content_length = -1; - ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(), - serialized_headers.size(), - &content_length, &output_headers)); - - // Should be back to the original headers. - EXPECT_EQ(content_length, kContentLength); - EXPECT_EQ(output_headers, input_headers); -} - -TEST(SpdyUtilsTest, SerializeAndParseValidTrailers) { - // Creates a SpdyHeaderBlock with some valid Trailers key->value pairs, - // serializes it, then parses the serialized output and verifies that the end - // result is the same as the trailers that the test started with. - SpdyHeaderBlock input_trailers; - const size_t kFinalOffset = 5678; - input_trailers[kFinalOffsetHeaderKey] = - QuicTextUtils::Uint64ToString(kFinalOffset); - input_trailers["key1"] = "value1"; - input_trailers["key2"] = "value2"; - - // Serialize the trailers. - string serialized_trailers = - SpdyUtils::SerializeUncompressedHeaders(input_trailers); - - // Take the serialized trailers, and parse back into a SpdyHeaderBlock. - SpdyHeaderBlock output_trailers; - size_t final_byte_offset = 0; - EXPECT_TRUE(SpdyUtils::ParseTrailers(serialized_trailers.data(), - serialized_trailers.size(), - &final_byte_offset, &output_trailers)); - - // Should be back to the original trailers, without the final offset header. - EXPECT_EQ(final_byte_offset, kFinalOffset); - input_trailers.erase(kFinalOffsetHeaderKey); - EXPECT_EQ(output_trailers, input_trailers); -} - -TEST(SpdyUtilsTest, SerializeAndParseTrailersWithoutFinalOffset) { - // Verifies that parsing fails if Trailers are missing a final offset header. - - SpdyHeaderBlock input_trailers; - input_trailers["key1"] = "value1"; - input_trailers["key2"] = "value2"; - - // Serialize the trailers. - string serialized_trailers = - SpdyUtils::SerializeUncompressedHeaders(input_trailers); - - // Parsing the serialized trailers fails because of the missing final offset. - SpdyHeaderBlock output_trailers; - size_t final_byte_offset = 0; - EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(), - serialized_trailers.size(), - &final_byte_offset, &output_trailers)); - EXPECT_EQ(final_byte_offset, 0u); -} - -TEST(SpdyUtilsTest, SerializeAndParseTrailersWithPseudoHeaders) { - // Verifies that parsing fails if Trailers include pseudo-headers. - - SpdyHeaderBlock input_trailers; - input_trailers[kFinalOffsetHeaderKey] = "12345"; - input_trailers[":disallowed-pseudo-header"] = "pseudo value"; - input_trailers["key1"] = "value1"; - input_trailers["key2"] = "value2"; - - // Serialize the trailers. - string serialized_trailers = - SpdyUtils::SerializeUncompressedHeaders(input_trailers); - - // Parsing the serialized trailers fails because of the extra pseudo header. - SpdyHeaderBlock output_trailers; - size_t final_byte_offset = 0; - EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(), - serialized_trailers.size(), - &final_byte_offset, &output_trailers)); -} static std::unique_ptr<QuicHeaderList> FromList( const QuicHeaderList::ListType& src) { std::unique_ptr<QuicHeaderList> headers(new QuicHeaderList);
diff --git a/net/quic/platform/api/quic_endian.h b/net/quic/platform/api/quic_endian.h index adf5c52..474143f 100644 --- a/net/quic/platform/api/quic_endian.h +++ b/net/quic/platform/api/quic_endian.h
@@ -9,6 +9,11 @@ namespace net { +enum Endianness { + NETWORK_BYTE_ORDER, // big endian + HOST_BYTE_ORDER // little endian +}; + // Provide utility functions that convert from/to network order (big endian) // to/from host order (can be either little or big endian depending on the // platform).
diff --git a/net/quic/platform/api/quic_mutex.h b/net/quic/platform/api/quic_mutex.h index cc51f30..b5d8d4b 100644 --- a/net/quic/platform/api/quic_mutex.h +++ b/net/quic/platform/api/quic_mutex.h
@@ -5,6 +5,7 @@ #ifndef NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_ #define NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_ +#include "base/macros.h" #include "net/quic/platform/impl/quic_mutex_impl.h" namespace net {
diff --git a/net/quic/platform/api/quic_ptr_util.h b/net/quic/platform/api/quic_ptr_util.h index b5a472e..89d931e 100644 --- a/net/quic/platform/api/quic_ptr_util.h +++ b/net/quic/platform/api/quic_ptr_util.h
@@ -4,18 +4,21 @@ #ifndef NET_QUIC_PLATFORM_API_QUIC_PTR_UTIL_H_ #define NET_QUIC_PLATFORM_API_QUIC_PTR_UTIL_H_ +#include <memory> +#include <utility> + #include "net/quic/platform/impl/quic_ptr_util_impl.h" namespace net { template <typename T, typename... Args> std::unique_ptr<T> QuicMakeUnique(Args&&... args) { - return std::move(QuicMakeUniqueImpl<T>(std::forward<Args>(args)...)); + return QuicMakeUniqueImpl<T>(std::forward<Args>(args)...); } template <typename T> std::unique_ptr<T> QuicWrapUnique(T* ptr) { - return std::move(QuicWrapUniqueImpl<T>(ptr)); + return QuicWrapUniqueImpl<T>(ptr); } } // namespace net
diff --git a/net/quic/platform/api/quic_str_cat.h b/net/quic/platform/api/quic_str_cat.h index ff60dac..9d6a970 100644 --- a/net/quic/platform/api/quic_str_cat.h +++ b/net/quic/platform/api/quic_str_cat.h
@@ -5,18 +5,21 @@ #ifndef NET_QUIC_PLATFORM_API_QUIC_STR_CAT_H_ #define NET_QUIC_PLATFORM_API_QUIC_STR_CAT_H_ +#include <string> +#include <utility> + #include "net/quic/platform/impl/quic_str_cat_impl.h" namespace net { template <typename... Args> inline std::string QuicStrCat(const Args&... args) { - return std::move(QuicStrCatImpl(std::forward<const Args&>(args)...)); + return QuicStrCatImpl(std::forward<const Args&>(args)...); } template <typename... Args> inline std::string QuicStringPrintf(const Args&... args) { - return std::move(QuicStringPrintfImpl(std::forward<const Args&>(args)...)); + return QuicStringPrintfImpl(std::forward<const Args&>(args)...); } } // namespace net
diff --git a/net/quic/platform/impl/quic_flag_utils_impl.h b/net/quic/platform/impl/quic_flag_utils_impl.h index ba6ddd9a..bd18794 100644 --- a/net/quic/platform/impl/quic_flag_utils_impl.h +++ b/net/quic/platform/impl/quic_flag_utils_impl.h
@@ -5,7 +5,8 @@ #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_ #define NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_ -#define QUIC_FLAG_COUNT_IMPL(flag) DVLOG(1) << "FLAG_##flag: " << FLAGS_##flag +#define QUIC_FLAG_COUNT_IMPL(flag) \ + DVLOG(1) << "FLAG_" #flag ": " << FLAGS_##flag #define QUIC_FLAG_COUNT_N_IMPL(flag, instance, total) QUIC_FLAG_COUNT_IMPL(flag) #endif // NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_
diff --git a/net/quic/platform/impl/quic_mutex_impl.h b/net/quic/platform/impl/quic_mutex_impl.h index 8053514e..9ad327c4 100644 --- a/net/quic/platform/impl/quic_mutex_impl.h +++ b/net/quic/platform/impl/quic_mutex_impl.h
@@ -5,6 +5,7 @@ #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_ #define NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_ +#include "base/macros.h" #include "base/synchronization/lock.h" #include "net/quic/platform/api/quic_export.h"
diff --git a/net/quic/platform/impl/quic_ptr_util_impl.h b/net/quic/platform/impl/quic_ptr_util_impl.h index b41ea4e..93fe585a 100644 --- a/net/quic/platform/impl/quic_ptr_util_impl.h +++ b/net/quic/platform/impl/quic_ptr_util_impl.h
@@ -10,12 +10,12 @@ template <typename T, typename... Args> std::unique_ptr<T> QuicMakeUniqueImpl(Args&&... args) { - return std::move(base::MakeUnique<T>(std::forward<Args>(args)...)); + return base::MakeUnique<T>(std::forward<Args>(args)...); } template <typename T> std::unique_ptr<T> QuicWrapUniqueImpl(T* ptr) { - return std::move(base::WrapUnique<T>(ptr)); + return base::WrapUnique<T>(ptr); } } // namespace net
diff --git a/net/quic/platform/impl/quic_str_cat_impl.h b/net/quic/platform/impl/quic_str_cat_impl.h index 3e07d64..fae149d 100644 --- a/net/quic/platform/impl/quic_str_cat_impl.h +++ b/net/quic/platform/impl/quic_str_cat_impl.h
@@ -22,7 +22,7 @@ template <typename... Args> inline std::string QuicStringPrintfImpl(const Args&... args) { - return std::move(base::StringPrintf(std::forward<const Args&>(args)...)); + return base::StringPrintf(std::forward<const Args&>(args)...); } } // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index f30363d1..837ef2f3 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -310,6 +310,7 @@ void(const QuicVersion& version)); MOCK_METHOD0(OnConfigNegotiated, void()); MOCK_METHOD0(PostProcessAfterData, void()); + MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void()); private: DISALLOW_COPY_AND_ASSIGN(MockQuicConnectionVisitor);
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index cf2df6e0..f216b8c8 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -126,6 +126,9 @@ return stop_waiting_frames_; } const std::vector<QuicPingFrame>& ping_frames() const { return ping_frames_; } + const std::vector<QuicWindowUpdateFrame>& window_update_frames() const { + return window_update_frames_; + } const std::vector<QuicPaddingFrame>& padding_frames() const { return padding_frames_; } @@ -211,6 +214,11 @@ return visitor_->ping_frames(); } +const std::vector<QuicWindowUpdateFrame>& +SimpleQuicFramer::window_update_frames() const { + return visitor_->window_update_frames(); +} + const std::vector<std::unique_ptr<QuicStreamFrame>>& SimpleQuicFramer::stream_frames() const { return visitor_->stream_frames();
diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h index e231bda..9e87523 100644 --- a/net/quic/test_tools/simple_quic_framer.h +++ b/net/quic/test_tools/simple_quic_framer.h
@@ -38,6 +38,7 @@ const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const; const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const; const std::vector<QuicPingFrame>& ping_frames() const; + const std::vector<QuicWindowUpdateFrame>& window_update_frames() const; const std::vector<QuicGoAwayFrame>& goaway_frames() const; const std::vector<QuicRstStreamFrame>& rst_stream_frames() const; const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const;
diff --git a/net/quic/test_tools/simulator/quic_endpoint.h b/net/quic/test_tools/simulator/quic_endpoint.h index 6f4f30d0..f3cbf4d0 100644 --- a/net/quic/test_tools/simulator/quic_endpoint.h +++ b/net/quic/test_tools/simulator/quic_endpoint.h
@@ -89,6 +89,7 @@ void OnConnectionMigration(PeerAddressChangeType type) override {} void OnPathDegrading() override {} void PostProcessAfterData() override {} + void OnAckNeedsRetransmittableFrame() override {} // End QuicConnectionVisitorInterface implementation. private:
diff --git a/net/spdy/core/spdy_header_indexing.cc b/net/spdy/core/spdy_header_indexing.cc deleted file mode 100644 index b528735..0000000 --- a/net/spdy/core/spdy_header_indexing.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/spdy/core/spdy_header_indexing.h" - -#include "net/spdy/core/spdy_bug_tracker.h" - -namespace net { - -int32_t FLAGS_gfe_spdy_indexing_set_bound = 50; -int32_t FLAGS_gfe_spdy_tracking_set_bound = 1000; - -HeaderIndexing::HeaderIndexing() - : indexing_set_bound_(FLAGS_gfe_spdy_indexing_set_bound), - tracking_set_bound_(FLAGS_gfe_spdy_tracking_set_bound) { - SPDY_BUG_IF(indexing_set_bound_ >= tracking_set_bound_) - << "Tracking set should be larger than indexing set"; -} - -HeaderIndexing::~HeaderIndexing() {} - -void HeaderIndexing::CreateInitIndexingHeaders() { - const SpdyString initial_fields[] = { - // Estimated top 100 fields. - "alt-svc", - "date", - "cache-control", - "content-type", - "expires", - "location", - "x-xss-protection", - "p3p", - "set-cookie", - "alternate-protocol", - "last-modified", - "server", - "x-snapchat-request-id", - "content-disposition", - "strict-transport-security", - "x-content-type-options", - "content-security-policy", - "x-frame-options", - "x-snapchat-notice", - "pragma", - ":status", - "content-length", - "etag", - "x-cloud-trace-context", - "vary", - "access-control-expose-headers", - "content-encoding", - "access-control-allow-origin", - "age", - ":protocol", - "via", - "x-robots-tag", - "link", - "access-control-allow-headers", - "x-google-session-info", - "x-google-backends", - "x-google-gfe-request-trace", - "warning", - "x-guploader-uploadid", - "x-cup-server-proof", - "timing-allow-origin", - "x-google-trace", - "access-control-allow-credentials", - "google-delayed-impression", - "google-creative-id", - "access-control-allow-methods", - "x-ua-compatible", - "x-google-gfe-response-code-details-trace", - "google-lineitem-id", - "version", - "x-google-dos-service-trace", - "x-google-service", - "x-google-gfe-service-trace", - "sane-time-millis", - "x-google-netmon-label", - "x-google-apiary-auth-scopes", - "x-seed-signature", - "content-security-policy-report-only", - "x-auto-login", - "x-original-content-length", - "accept-ranges", - "x-goog-hash", - "x-google-gfe-response-body-transformations", - "cf-ray", - "x-content-security-policy-report-only", - "x-google-shellfish-status", - "x-amz-id-2", - "get-dictionary", - "grpc-message", - "x-hw", - "x-google-gfe-backend-request-info", - "x-goog-upload-header-x-google-session-info", - "x-amz-cf-id", - "x-powered-by", - "www-authenticate", - "access-control-max-age", - "x-spf-response-type", - "x-goog-meta-encoded_request", - "x-goog-generation", - "x-google-gslb-service", - "x-google-servertype", - "x-cache", - "x-chromium-appcache-fallback-override", - "x-goog-upload-url", - "x-goog-upload-control-url", - "content-range", - "x-seen-by", - "x-google-apps-framework-action", - "content-location", - "x-daystart", - "x-varnish", - "fastly-debug-digest", - "x-daynum", - "x-goog-stored-content-encoding", - "x-goog-storage-class", - "x-google-cookies-blocked", - "x-range-md5", - "x-served-by", - "x-client-wire-protocol", - "content-language", - }; - - indexing_set_.clear(); - indexing_set_ = - HeaderSet(initial_fields, initial_fields + arraysize(initial_fields)); - tracking_set_ = - HeaderSet(initial_fields, initial_fields + arraysize(initial_fields)); -} - -bool HeaderIndexing::ShouldIndex(SpdyStringPiece header, - SpdyStringPiece /* value */) { - total_header_count_++; - if (header.empty()) { - return false; - } - // header is in indexing set. - SpdyString header_str(header.data(), header.size()); - if (indexing_set_.find(header_str) != indexing_set_.end()) { - return true; - } - // header not in indexing set. Check tracking set. - if (tracking_set_.find(header_str) != tracking_set_.end()) { - // Seen this header before. Add it to indexing set. - TryInsertHeader(std::move(header_str), &indexing_set_, indexing_set_bound_); - missed_header_in_tracking_++; - } else { - // Add header to tracking set. - TryInsertHeader(std::move(header_str), &tracking_set_, tracking_set_bound_); - missed_header_in_indexing_++; - } - return false; -} - -void HeaderIndexing::TryInsertHeader(SpdyString&& header, - HeaderSet* set, - size_t bound) { - std::pair<HeaderSet::iterator, bool> result = set->insert(std::move(header)); - if (set->size() > bound) { - // Reach the size limit. Remove the header next to the newly added header. - // If the new header is at the end, look for the "next" element at the - // beginning. - HeaderSet::iterator it = std::next(result.first); - if (it != set->end()) { - set->erase(it); - } else { - set->erase(set->begin()); - } - } -} - -} // namespace net
diff --git a/net/spdy/core/spdy_header_indexing.h b/net/spdy/core/spdy_header_indexing.h deleted file mode 100644 index 2e42155..0000000 --- a/net/spdy/core/spdy_header_indexing.h +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_SPDY_CORE_SPDY_HEADER_INDEXING_H_ -#define NET_SPDY_CORE_SPDY_HEADER_INDEXING_H_ - -#include <stdint.h> -#include <memory> -#include <unordered_set> -#include <utility> - -#include "net/spdy/platform/api/spdy_export.h" -#include "net/spdy/platform/api/spdy_string.h" -#include "net/spdy/platform/api/spdy_string_piece.h" - -namespace net { - -namespace test { -class HeaderIndexingPeer; -} - -SPDY_EXPORT_PRIVATE extern int32_t FLAGS_gfe_spdy_indexing_set_bound; -SPDY_EXPORT_PRIVATE extern int32_t FLAGS_gfe_spdy_tracking_set_bound; - -// Maintain two headers sets: Indexing set and tracking -// set. Call ShouldIndex() for each header to decide if to index it. If for some -// connections, we decide to index all headers, we may still want to call -// UpdateSets to log the headers into both sets. -class SPDY_EXPORT_PRIVATE HeaderIndexing { - public: - using HeaderSet = std::unordered_set<SpdyString>; - - HeaderIndexing(); - ~HeaderIndexing(); - - void CreateInitIndexingHeaders(); - - // Decide if a header should be indexed. We only use |header|. Add |value| to - // be consistent with HPACK indexing policy interface. - bool ShouldIndex(SpdyStringPiece header, SpdyStringPiece value); - - // Not to make the indexing decision but to update sets. - void UpdateSets(SpdyStringPiece header, SpdyStringPiece value) { - update_only_header_count_++; - ShouldIndex(header, value); - } - - int64_t total_header_count() { return total_header_count_; } - int64_t update_only_header_count() { return update_only_header_count_; } - int64_t missed_headers_in_indexing() { return missed_header_in_indexing_; } - int64_t missed_headers_in_tracking() { return missed_header_in_tracking_; } - - private: - friend class test::HeaderIndexingPeer; - void TryInsertHeader(SpdyString&& header, HeaderSet* set, size_t bound); - // Headers to index. - HeaderSet indexing_set_; - // Headers seen so far. - HeaderSet tracking_set_; - const size_t indexing_set_bound_; - const size_t tracking_set_bound_; - int64_t total_header_count_ = 0; - int64_t update_only_header_count_ = 0; - int64_t missed_header_in_indexing_ = 0; - int64_t missed_header_in_tracking_ = 0; -}; - -} // namespace net - -#endif // NET_SPDY_CORE_SPDY_HEADER_INDEXING_H_
diff --git a/net/spdy/core/spdy_header_indexing_test.cc b/net/spdy/core/spdy_header_indexing_test.cc deleted file mode 100644 index 724bba41..0000000 --- a/net/spdy/core/spdy_header_indexing_test.cc +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/spdy/core/spdy_header_indexing.h" - -#include "base/memory/ptr_util.h" -#include "net/spdy/platform/api/spdy_ptr_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/platform_test.h" - -namespace net { - -namespace test { - -class HeaderIndexingPeer { - public: - HeaderIndexingPeer() : hi_() {} - - void CreateTestInit() { - SpdyString input[] = {"key1", "key2", "key3"}; - hi_.indexing_set_ = - HeaderIndexing::HeaderSet(input, input + arraysize(input)); - hi_.tracking_set_ = - HeaderIndexing::HeaderSet(input, input + arraysize(input)); - } - - bool ShouldIndex(SpdyStringPiece header) { - return hi_.ShouldIndex(header, ""); - } - - void CreateInitIndexingHeaders() { hi_.CreateInitIndexingHeaders(); } - - void TryInsert(SpdyString&& header) { - hi_.TryInsertHeader(std::move(header), &(hi_.indexing_set_), - hi_.indexing_set_bound_); - } - - bool InTrackingSet(const SpdyString& str) { - return hi_.tracking_set_.find(str) != hi_.tracking_set_.end(); - } - - size_t indexing_set_size() const { return hi_.indexing_set_.size(); } - - size_t tracking_set_size() const { return hi_.tracking_set_.size(); } - - HeaderIndexing::HeaderSet* indexing_set() { return &(hi_.indexing_set_); } - - HeaderIndexing::HeaderSet* tracking_set() { return &(hi_.tracking_set_); } - - private: - HeaderIndexing hi_; -}; - -class SpdyHeaderIndexingTest : public ::testing::Test { - protected: - SpdyHeaderIndexingTest() { - FLAGS_gfe_spdy_indexing_set_bound = 3; - FLAGS_gfe_spdy_tracking_set_bound = 4; - hi_ = SpdyMakeUnique<HeaderIndexingPeer>(); - hi_->CreateTestInit(); - } - void SetUp() override { - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(3u, hi_->tracking_set_size()); - } - std::unique_ptr<HeaderIndexingPeer> hi_; -}; - -TEST_F(SpdyHeaderIndexingTest, TestTryInsertHeader) { - SpdyString key("key4"); - hi_->TryInsert(std::move(key)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_TRUE(hi_->ShouldIndex("key4")); -} - -TEST_F(SpdyHeaderIndexingTest, TestShouldIndex) { - SpdyString key3 = "key3"; - SpdyString key4 = "key4"; - SpdyString key5 = "key5"; - // Cache hit. - EXPECT_TRUE(hi_->ShouldIndex(key3)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(3u, hi_->tracking_set_size()); - - // Cache miss. Add to tracking set. - EXPECT_FALSE(hi_->ShouldIndex(key4)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(4u, hi_->tracking_set_size()); - EXPECT_TRUE(hi_->InTrackingSet(key4)); - // Cache miss. Add to indexing set by kicking one entry out. - EXPECT_FALSE(hi_->ShouldIndex(key4)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(4u, hi_->tracking_set_size()); - EXPECT_TRUE(hi_->InTrackingSet(key4)); - // Cache hit. - EXPECT_TRUE(hi_->ShouldIndex(key4)); - - // Cache miss. Add to tracking set by kicking one entry out. - EXPECT_FALSE(hi_->ShouldIndex(key5)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(4u, hi_->tracking_set_size()); - EXPECT_TRUE(hi_->ShouldIndex(key4)); - EXPECT_TRUE(hi_->InTrackingSet(key5)); - // Cache miss. Add to indexing set by kicking one entry out. - EXPECT_FALSE(hi_->ShouldIndex(key5)); - EXPECT_EQ(3u, hi_->indexing_set_size()); - EXPECT_EQ(4u, hi_->tracking_set_size()); - EXPECT_TRUE(hi_->ShouldIndex(key5)); - EXPECT_TRUE(hi_->InTrackingSet(key5)); -} - -TEST_F(SpdyHeaderIndexingTest, TestSetInit) { - hi_->CreateInitIndexingHeaders(); - EXPECT_EQ(100u, hi_->indexing_set_size()); - EXPECT_EQ(100u, hi_->tracking_set_size()); - EXPECT_TRUE(hi_->ShouldIndex(":status")); - EXPECT_TRUE(hi_->InTrackingSet(":status")); - EXPECT_FALSE(hi_->InTrackingSet("NotValid")); - EXPECT_FALSE(hi_->ShouldIndex("NotValid")); -} - -} // namespace test - -} // namespace net
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index db3b8f9..255d1b7 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -2003,7 +2003,6 @@ GetPeerInMemoryConnectionId(connection_id); header.public_header.reset_flag = true; header.public_header.version_flag = false; - header.rejected_packet_number = 10101; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), Perspective::IS_SERVER); std::unique_ptr<QuicEncryptedPacket> packet( @@ -2037,7 +2036,6 @@ GetPeerInMemoryConnectionId(incorrect_connection_id); header.public_header.reset_flag = true; header.public_header.version_flag = false; - header.rejected_packet_number = 10101; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), Perspective::IS_SERVER); std::unique_ptr<QuicEncryptedPacket> packet( @@ -2073,7 +2071,6 @@ header.public_header.connection_id = incorrect_connection_id; header.public_header.reset_flag = true; header.public_header.version_flag = false; - header.rejected_packet_number = 10101; QuicFramer framer(server_supported_versions_, QuicTime::Zero(), Perspective::IS_CLIENT); std::unique_ptr<QuicEncryptedPacket> packet( @@ -3023,6 +3020,48 @@ client_->connection_error()); } +class WindowUpdateObserver : public QuicConnectionDebugVisitor { + public: + WindowUpdateObserver() : num_window_update_frames_(0) {} + + size_t num_window_update_frames() const { return num_window_update_frames_; } + + void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { + ++num_window_update_frames_; + } + + private: + size_t num_window_update_frames_; +}; + +TEST_P(EndToEndTest, WindowUpdateInAck) { + FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + WindowUpdateObserver observer; + QuicConnection* client_connection = + client_->client()->session()->connection(); + client_connection->set_debug_visitor(&observer); + QuicVersion version = client_connection->version(); + // 100KB body. + string body(100 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + client_->Disconnect(); + if (version > QUIC_VERSION_38) { + EXPECT_LT(0u, observer.num_window_update_frames()); + } else { + EXPECT_EQ(0u, observer.num_window_update_frames()); + } +} + class EndToEndBufferedPacketsTest : public EndToEndTest { public: void CreateClientWithWriter() override {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index b60833dab..12061ae 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -199,8 +199,8 @@ QuicSpdyClientStream* stream = session_->CreateOutgoingDynamicStream(kDefaultPriority); - ASSERT_TRUE(stream); - EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority)); + ASSERT_NE(nullptr, stream); + EXPECT_EQ(nullptr, session_->CreateOutgoingDynamicStream(kDefaultPriority)); // Close the stream and receive an RST frame to remove the unfinished stream session_->CloseStream(stream->id()); @@ -209,7 +209,81 @@ // Check that a new one can be created. EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); stream = session_->CreateOutgoingDynamicStream(kDefaultPriority); - EXPECT_TRUE(stream); + EXPECT_NE(nullptr, stream); +} + +TEST_P(QuicClientSessionTest, ResetAndTrailers) { + // Tests the situation in which the client sends a RST at the same time that + // the server sends trailing headers (trailers). Receipt of the trailers by + // the client should result in all outstanding stream state being tidied up + // (including flow control, and number of available outgoing streams). + const uint32_t kServerMaxIncomingStreams = 1; + CompleteCryptoHandshake(kServerMaxIncomingStreams); + + QuicSpdyClientStream* stream = + session_->CreateOutgoingDynamicStream(kDefaultPriority); + ASSERT_NE(nullptr, stream); + EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority)); + + QuicStreamId stream_id = stream->id(); + EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(1); + session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + + // A new stream cannot be created as the reset stream still counts as an open + // outgoing stream until closed by the server. + EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams()); + stream = session_->CreateOutgoingDynamicStream(kDefaultPriority); + EXPECT_EQ(nullptr, stream); + + // The stream receives trailers with final byte offset: this is one of three + // ways that a peer can signal the end of a stream (the others being RST, + // stream data + FIN). + QuicHeaderList trailers; + trailers.OnHeaderBlockStart(); + trailers.OnHeader(kFinalOffsetHeaderKey, "0"); + trailers.OnHeaderBlockEnd(0); + session_->OnStreamHeaderList(stream_id, /*fin=*/false, 0, trailers); + + if (FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers) { + // The stream is now complete from the client's perspective, and it should + // be able to create a new outgoing stream. + EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); + stream = session_->CreateOutgoingDynamicStream(kDefaultPriority); + EXPECT_NE(nullptr, stream); + } else { + // The old behavior: receiving trailers with final offset does not trigger + // cleanup of local stream state. New streams cannot be created. + EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams()); + stream = session_->CreateOutgoingDynamicStream(kDefaultPriority); + EXPECT_EQ(nullptr, stream); + } +} + +TEST_P(QuicClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) { + // Tests the situation where the client has sent a RST to the server, and has + // received trailing headers with a malformed final byte offset value. + FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers = true; + CompleteCryptoHandshake(); + + QuicSpdyClientStream* stream = + session_->CreateOutgoingDynamicStream(kDefaultPriority); + ASSERT_NE(nullptr, stream); + + // Send the RST, which results in the stream being closed locally (but some + // state remains while the client waits for a response from the server). + QuicStreamId stream_id = stream->id(); + EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(1); + session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + + // The stream receives trailers with final byte offset, but the header value + // is non-numeric and should be treated as malformed. + QuicHeaderList trailers; + trailers.OnHeaderBlockStart(); + trailers.OnHeader(kFinalOffsetHeaderKey, "invalid non-numeric value"); + trailers.OnHeaderBlockEnd(0); + + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); + session_->OnStreamHeaderList(stream_id, /*fin=*/false, 0, trailers); } TEST_P(QuicClientSessionTest, GoAwayReceived) {
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 6721c07..5e325f353 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -336,10 +336,9 @@ if (time_wait_list_manager_->IsConnectionIdInTimeWait( header.public_header.connection_id)) { // This connection ID is already in time-wait state. - time_wait_list_manager_->ProcessPacket( - current_server_address_, current_client_address_, - header.public_header.connection_id, header.packet_number, - *current_packet_); + time_wait_list_manager_->ProcessPacket(current_server_address_, + current_client_address_, + header.public_header.connection_id); return false; } @@ -348,11 +347,12 @@ if (fate == kFateProcess) { // Execute stateless rejection logic to determine the packet fate, then // invoke ProcessUnauthenticatedHeaderFate. - MaybeRejectStatelessly(connection_id, header); + MaybeRejectStatelessly(connection_id, + header.public_header.versions.front()); } else { // If the fate is already known, process it without executing stateless // rejection logic. - ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number); + ProcessUnauthenticatedHeaderFate(fate, connection_id); } return false; @@ -360,11 +360,10 @@ void QuicDispatcher::ProcessUnauthenticatedHeaderFate( QuicPacketFate fate, - QuicConnectionId connection_id, - QuicPacketNumber packet_number) { + QuicConnectionId connection_id) { switch (fate) { case kFateProcess: { - ProcessChlo(packet_number); + ProcessChlo(); break; } case kFateTimeWait: @@ -382,8 +381,7 @@ } DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); time_wait_list_manager_->ProcessPacket( - current_server_address_, current_client_address_, connection_id, - packet_number, *current_packet_); + current_server_address_, current_client_address_, connection_id); // Any packets which were buffered while the stateless rejector logic was // running should be discarded. Do not inform the time wait list manager, @@ -717,7 +715,7 @@ } } -void QuicDispatcher::ProcessChlo(QuicPacketNumber packet_number) { +void QuicDispatcher::ProcessChlo() { if (!accept_new_connections_) { // Don't any create new connection. time_wait_list_manager()->AddConnectionIdToTimeWait( @@ -725,9 +723,9 @@ /*connection_rejected_statelessly=*/false, /*termination_packets=*/nullptr); // This will trigger sending Public Reset packet. - time_wait_list_manager()->ProcessPacket( - current_server_address(), current_client_address(), - current_connection_id(), packet_number, current_packet()); + time_wait_list_manager()->ProcessPacket(current_server_address(), + current_client_address(), + current_connection_id()); return; } if (FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && @@ -815,20 +813,18 @@ : public StatelessRejector::ProcessDoneCallback { public: StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, - QuicPacketNumber packet_number, QuicVersion first_version) : dispatcher_(dispatcher), current_client_address_(dispatcher->current_client_address_), current_server_address_(dispatcher->current_server_address_), current_packet_( dispatcher->current_packet_->Clone()), // Note: copies the packet - packet_number_(packet_number), first_version_(first_version) {} void Run(std::unique_ptr<StatelessRejector> rejector) override { dispatcher_->OnStatelessRejectorProcessDone( std::move(rejector), current_client_address_, current_server_address_, - std::move(current_packet_), packet_number_, first_version_); + std::move(current_packet_), first_version_); } private: @@ -836,12 +832,11 @@ QuicSocketAddress current_client_address_; QuicSocketAddress current_server_address_; std::unique_ptr<QuicReceivedPacket> current_packet_; - QuicPacketNumber packet_number_; QuicVersion first_version_; }; void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, - const QuicPacketHeader& header) { + QuicVersion version) { // TODO(rch): This logic should probably live completely inside the rejector. if (!FLAGS_quic_allow_chlo_buffering || !FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || @@ -852,26 +847,23 @@ !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), nullptr)) { // Buffer non-CHLO packets. - ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, - header.packet_number); + ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); return; } - ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, - header.packet_number); + ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id); return; } std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( - header.public_header.versions.front(), GetSupportedVersions(), - crypto_config_, &compressed_certs_cache_, helper()->GetClock(), - helper()->GetRandomGenerator(), current_packet_->length(), - current_client_address_, current_server_address_)); + version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_, + helper()->GetClock(), helper()->GetRandomGenerator(), + current_packet_->length(), current_client_address_, + current_server_address_)); ChloValidator validator(session_helper_.get(), current_server_address_, rejector.get()); if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), &validator)) { - ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, - header.packet_number); + ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); return; } @@ -882,16 +874,14 @@ terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, validator.error_details()); OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED); - ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, - header.packet_number); + ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id); return; } // If we were able to make a decision about this CHLO based purely on the // information available in OnChlo, just invoke the done callback immediately. if (rejector->state() != StatelessRejector::UNKNOWN) { - ProcessStatelessRejectorState(std::move(rejector), header.packet_number, - header.public_header.versions.front()); + ProcessStatelessRejectorState(std::move(rejector), version); return; } @@ -904,8 +894,7 @@ // Continue stateless rejector processing std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( - new StatelessRejectorProcessDoneCallback( - this, header.packet_number, header.public_header.versions.front())); + new StatelessRejectorProcessDoneCallback(this, version)); StatelessRejector::Process(std::move(rejector), std::move(cb)); } @@ -914,7 +903,6 @@ const QuicSocketAddress& current_client_address, const QuicSocketAddress& current_server_address, std::unique_ptr<QuicReceivedPacket> current_packet, - QuicPacketNumber packet_number, QuicVersion first_version) { // Stop buffering packets on this connection const auto num_erased = @@ -927,9 +915,9 @@ // don't proceed. if (time_wait_list_manager_->IsConnectionIdInTimeWait( rejector->connection_id())) { - time_wait_list_manager_->ProcessPacket( - current_server_address, current_client_address, - rejector->connection_id(), packet_number, *current_packet); + time_wait_list_manager_->ProcessPacket(current_server_address, + current_client_address, + rejector->connection_id()); return; } @@ -940,13 +928,11 @@ current_packet_ = current_packet.get(); current_connection_id_ = rejector->connection_id(); - ProcessStatelessRejectorState(std::move(rejector), packet_number, - first_version); + ProcessStatelessRejectorState(std::move(rejector), first_version); } void QuicDispatcher::ProcessStatelessRejectorState( std::unique_ptr<StatelessRejector> rejector, - QuicPacketNumber packet_number, QuicVersion first_version) { QuicPacketFate fate; switch (rejector->state()) { @@ -988,8 +974,7 @@ fate = kFateDrop; break; } - ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), - packet_number); + ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id()); } const QuicVersionVector& QuicDispatcher::GetSupportedVersions() {
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 132cd28..210d4ea4 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h
@@ -204,7 +204,7 @@ // Called when |current_packet_| is a CHLO packet. Creates a new connection // and delivers any buffered packets for that connection id. - void ProcessChlo(QuicPacketNumber packet_number); + void ProcessChlo(); QuicTimeWaitListManager* time_wait_list_manager() { return time_wait_list_manager_.get(); @@ -296,7 +296,7 @@ // fate which describes what subsequent processing should be performed on the // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate. void MaybeRejectStatelessly(QuicConnectionId connection_id, - const QuicPacketHeader& header); + QuicVersion version); // Deliver |packets| to |session| for further processing. void DeliverPacketsToSession( @@ -306,8 +306,7 @@ // Perform the appropriate actions on the current packet based on |fate| - // either process, buffer, or drop it. void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate, - QuicConnectionId connection_id, - QuicPacketNumber packet_number); + QuicConnectionId connection_id); // Invoked when StatelessRejector::Process completes. void OnStatelessRejectorProcessDone( @@ -315,14 +314,12 @@ const QuicSocketAddress& current_client_address, const QuicSocketAddress& current_server_address, std::unique_ptr<QuicReceivedPacket> current_packet, - QuicPacketNumber packet_number, QuicVersion first_version); // Examine the state of the rejector and decide what to do with the current // packet. void ProcessStatelessRejectorState( std::unique_ptr<StatelessRejector> rejector, - QuicPacketNumber packet_number, QuicVersion first_version); void set_new_sessions_allowed_per_event_loop(
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 2b582dd..d4bb849 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -428,7 +428,6 @@ packet.public_header.connection_id = connection_id; packet.public_header.reset_flag = true; packet.public_header.version_flag = false; - packet.rejected_packet_number = 19191; packet.nonce_proof = 132232; std::unique_ptr<QuicEncryptedPacket> encrypted( QuicFramer::BuildPublicResetPacket(packet)); @@ -450,8 +449,7 @@ // Dispatcher forwards subsequent packets for this connection_id to the time // wait list manager. - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id)) .Times(1); EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); @@ -466,8 +464,7 @@ // Dispatcher forwards all packets for this connection_id to the time wait // list manager. EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id)) .Times(1); EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(1); @@ -482,7 +479,7 @@ // dispatcher_ should drop this packet. EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); ProcessPacket(client_address, 1, true, SerializeCHLO()); @@ -519,8 +516,7 @@ // Dispatcher forwards this packet for this connection_id to the time wait // list manager. EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id)) .Times(1); EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(1); @@ -535,7 +531,7 @@ static_assert(arraysize(kSupportedQuicVersions) == 5u, "Supported versions out of sync"); FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_enable_version_39 = true; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); QuicConnectionId connection_id = 1; @@ -575,7 +571,7 @@ PACKET_6BYTE_PACKET_NUMBER, 1); // Turn off version 39. - FLAGS_quic_enable_version_39 = false; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; ++connection_id; EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address)) .Times(0); @@ -584,7 +580,7 @@ PACKET_6BYTE_PACKET_NUMBER, 1); // Turn on version 39. - FLAGS_quic_enable_version_39 = true; + FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; ++connection_id; EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address)) .WillOnce(testing::Return(CreateSession( @@ -753,8 +749,7 @@ time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); if (ExpectStatelessReject()) { // The second packet will be processed on the time-wait list. - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id)) .Times(1); } else { // The second packet will trigger a packet-validation @@ -865,8 +860,7 @@ QuicConnectionId connection_id = 1; // Dispatcher drops this packet. EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id)) .Times(0); EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _)) .Times(0); @@ -1351,7 +1345,7 @@ // New arrived CHLO will be dropped because this connection is in time wait // list. ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _)); + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id)); ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); } @@ -1709,13 +1703,13 @@ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(conn_id, _, true, _)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); + ProcessPacket(_, client_addr_, conn_id)); EXPECT_CALL(check, Call(2)); EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_)) .Times(0); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); + ProcessPacket(_, client_addr_, conn_id)); } // Send a CHLO that the StatelessRejector will reject. @@ -1831,11 +1825,11 @@ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(conn_id_2, _, true, _)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); + ProcessPacket(_, client_addr_, conn_id_2)); EXPECT_CALL(check, Call(2)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); + ProcessPacket(_, client_addr_, conn_id_2)); EXPECT_CALL(check, Call(3)); EXPECT_CALL(*dispatcher_, @@ -1845,7 +1839,7 @@ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(conn_id_1, _, true, _)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); + ProcessPacket(_, client_addr_, conn_id_1)); } // Send a CHLO that the StatelessRejector will reject. @@ -1904,7 +1898,7 @@ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(conn_id_1, _, true, _)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); + ProcessPacket(_, client_addr_, conn_id_1)); } // Send a CHLO that the StatelessRejector will reject. @@ -1944,7 +1938,7 @@ EXPECT_CALL(check, Call(2)); EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); + ProcessPacket(_, client_addr_, conn_id)); EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_)) .Times(0); }
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index 4fa077f..04ce85b 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -147,9 +147,7 @@ void QuicTimeWaitListManager::ProcessPacket( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber packet_number, - const QuicEncryptedPacket& /*packet*/) { + QuicConnectionId connection_id) { DCHECK(IsConnectionIdInTimeWait(connection_id)); QUIC_DLOG(INFO) << "Processing " << connection_id << " in time wait state."; // TODO(satyamshekhar): Think about handling packets from different client @@ -177,7 +175,7 @@ return; } - SendPublicReset(server_address, client_address, connection_id, packet_number); + SendPublicReset(server_address, client_address, connection_id); } void QuicTimeWaitListManager::SendVersionNegotiationPacket( @@ -200,13 +198,11 @@ void QuicTimeWaitListManager::SendPublicReset( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber rejected_packet_number) { + QuicConnectionId connection_id) { QuicPublicResetPacket packet; packet.public_header.connection_id = connection_id; packet.public_header.reset_flag = true; packet.public_header.version_flag = false; - packet.rejected_packet_number = rejected_packet_number; // TODO(satyamshekhar): generate a valid nonce for this connection_id. packet.nonce_proof = 1010101; packet.client_address = client_address;
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h index 6e611796..f2eb505 100644 --- a/net/tools/quic/quic_time_wait_list_manager.h +++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -85,9 +85,7 @@ // state. virtual to override in tests. virtual void ProcessPacket(const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber packet_number, - const QuicEncryptedPacket& packet); + QuicConnectionId connection_id); // Called by the dispatcher when the underlying socket becomes writable again, // since we might need to send pending public reset packets which we didn't @@ -124,8 +122,7 @@ // Creates a public reset packet and sends it or queues it to be sent later. virtual void SendPublicReset(const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber rejected_packet_number); + QuicConnectionId connection_id); private: friend class test::QuicDispatcherPeer;
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index 96d74d0d..f76c51c 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -114,11 +114,9 @@ return time_wait_list_manager_.IsConnectionIdInTimeWait(connection_id); } - void ProcessPacket(QuicConnectionId connection_id, - QuicPacketNumber packet_number) { - QuicEncryptedPacket packet(nullptr, 0); + void ProcessPacket(QuicConnectionId connection_id) { time_wait_list_manager_.ProcessPacket(server_address_, client_address_, - connection_id, packet_number, packet); + connection_id); } QuicEncryptedPacket* ConstructEncryptedPacket( @@ -144,9 +142,8 @@ class ValidatePublicResetPacketPredicate : public MatcherInterface<const std::tr1::tuple<const char*, int>> { public: - explicit ValidatePublicResetPacketPredicate(QuicConnectionId connection_id, - QuicPacketNumber number) - : connection_id_(connection_id), packet_number_(number) {} + explicit ValidatePublicResetPacketPredicate(QuicConnectionId connection_id) + : connection_id_(connection_id) {} bool MatchAndExplain( const std::tr1::tuple<const char*, int> packet_buffer, @@ -163,7 +160,6 @@ packet.public_header.connection_id) && packet.public_header.reset_flag && !packet.public_header.version_flag && - packet_number_ == packet.rejected_packet_number && net::test::TestPeerIPAddress() == packet.client_address.host() && kTestPort == packet.client_address.port(); } @@ -174,14 +170,11 @@ private: QuicConnectionId connection_id_; - QuicPacketNumber packet_number_; }; Matcher<const std::tr1::tuple<const char*, int>> PublicResetPacketEq( - QuicConnectionId connection_id, - QuicPacketNumber packet_number) { - return MakeMatcher( - new ValidatePublicResetPacketPredicate(connection_id, packet_number)); + QuicConnectionId connection_id) { + return MakeMatcher(new ValidatePublicResetPacketPredicate(connection_id)); } TEST_F(QuicTimeWaitListManagerTest, CheckConnectionIdInTimeWait) { @@ -223,12 +216,11 @@ AddConnectionId(connection_id_, QuicVersionMax(), /*connection_rejected_statelessly=*/false, &termination_packets); - const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, server_address_.host(), client_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); - ProcessPacket(connection_id_, kRandomSequenceNumber); + ProcessPacket(connection_id_); } TEST_F(QuicTimeWaitListManagerTest, SendTwoConnectionCloses) { @@ -244,25 +236,23 @@ AddConnectionId(connection_id_, QuicVersionMax(), /*connection_rejected_statelessly=*/false, &termination_packets); - const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, server_address_.host(), client_address_, _)) .Times(2) .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 1))); - ProcessPacket(connection_id_, kRandomSequenceNumber); + ProcessPacket(connection_id_); } TEST_F(QuicTimeWaitListManagerTest, SendPublicReset) { EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); AddConnectionId(connection_id_); - const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id_, 0))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id_))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); - ProcessPacket(connection_id_, kRandomSequenceNumber); + ProcessPacket(connection_id_); } TEST_F(QuicTimeWaitListManagerTest, SendPublicResetWithExponentialBackOff) { @@ -274,7 +264,7 @@ EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); } - ProcessPacket(connection_id_, packet_number); + ProcessPacket(connection_id_); // Send public reset with exponential back off. if ((packet_number & (packet_number - 1)) == 0) { EXPECT_TRUE(QuicTimeWaitListManagerPeer::ShouldSendResponse( @@ -289,13 +279,12 @@ TEST_F(QuicTimeWaitListManagerTest, NoPublicResetForStatelessConnections) { EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); AddStatelessConnectionId(connection_id_); - const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); - ProcessPacket(connection_id_, kRandomSequenceNumber); + ProcessPacket(connection_id_); } TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) { @@ -354,20 +343,20 @@ // Let first write through. EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length()))); - ProcessPacket(connection_id, packet_number); + ProcessPacket(connection_id); // write block for the next packet. EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id))) .WillOnce(DoAll(Assign(&writer_is_blocked_, true), Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN)))); EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_)); - ProcessPacket(connection_id, packet_number); + ProcessPacket(connection_id); // 3rd packet. No public reset should be sent; - ProcessPacket(connection_id, packet_number); + ProcessPacket(connection_id); // write packet should not be called since we are write blocked but the // should be queued. @@ -379,18 +368,18 @@ ConstructEncryptedPacket(other_connection_id, other_packet_number)); EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0); EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_)); - ProcessPacket(other_connection_id, other_packet_number); + ProcessPacket(other_connection_id); EXPECT_EQ(2u, time_wait_list_manager_.num_connections()); // Now expect all the write blocked public reset packets to be sent again. writer_is_blocked_ = false; EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length()))); EXPECT_CALL(writer_, WritePacket(_, _, server_address_.host(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(other_connection_id, 0))) + .With(Args<0, 1>(PublicResetPacketEq(other_connection_id))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, other_packet->length()))); time_wait_list_manager_.OnCanWrite(); } @@ -442,8 +431,7 @@ server_address_.host(), client_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); - const int kRandomSequenceNumber = 1; - ProcessPacket(connection_id_, kRandomSequenceNumber); + ProcessPacket(connection_id_); const QuicTime::Delta time_wait_period = QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
diff --git a/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h b/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h index a2d7fa6..5e1f5cf 100644 --- a/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h
@@ -36,12 +36,10 @@ termination_packets); } - MOCK_METHOD5(ProcessPacket, + MOCK_METHOD3(ProcessPacket, void(const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber packet_number, - const QuicEncryptedPacket& packet)); + QuicConnectionId connection_id)); MOCK_METHOD4(SendVersionNegotiationPacket, void(QuicConnectionId connection_id,
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc index cf7dfe7cc..7f693c6d 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -86,10 +86,9 @@ QuicDispatcher* dispatcher, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber rejected_packet_number) { + QuicConnectionId connection_id) { dispatcher->time_wait_list_manager()->SendPublicReset( - server_address, client_address, connection_id, rejected_packet_number); + server_address, client_address, connection_id); } } // namespace test
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h index f035a5c..9353a60 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.h +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -52,8 +52,7 @@ static void SendPublicReset(QuicDispatcher* dispatcher, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - QuicPacketNumber rejected_packet_number); + QuicConnectionId connection_id); private: DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 3e86670..0655c80 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -243,7 +243,6 @@ for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) { stream.second->set_visitor(nullptr); } - client_->Disconnect(); } void QuicTestClient::Initialize() {
diff --git a/net/url_request/report_sender.cc b/net/url_request/report_sender.cc index 6c3bee4..7bf712e 100644 --- a/net/url_request/report_sender.cc +++ b/net/url_request/report_sender.cc
@@ -41,10 +41,8 @@ namespace net { -ReportSender::ReportSender(URLRequestContext* request_context, - CookiesPreference cookies_preference) - : request_context_(request_context), - cookies_preference_(cookies_preference) {} +ReportSender::ReportSender(URLRequestContext* request_context) + : request_context_(request_context) {} ReportSender::~ReportSender() { } @@ -61,12 +59,9 @@ &kUserDataKey, base::MakeUnique<CallbackInfo>(success_callback, error_callback)); - int load_flags = - LOAD_BYPASS_CACHE | LOAD_DISABLE_CACHE | LOAD_DO_NOT_SEND_AUTH_DATA; - if (cookies_preference_ != SEND_COOKIES) { - load_flags |= LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES; - } - url_request->SetLoadFlags(load_flags); + url_request->SetLoadFlags( + LOAD_BYPASS_CACHE | LOAD_DISABLE_CACHE | LOAD_DO_NOT_SEND_AUTH_DATA | + LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES); HttpRequestHeaders extra_headers; extra_headers.SetHeader(HttpRequestHeaders::kContentType, content_type);
diff --git a/net/url_request/report_sender.h b/net/url_request/report_sender.h index 6bfc72c..7ba8302c 100644 --- a/net/url_request/report_sender.h +++ b/net/url_request/report_sender.h
@@ -34,15 +34,10 @@ using ErrorCallback = base::Callback< void(const GURL&, int /* net_error */, int /* http_response_code */)>; - // Represents whether or not to send cookies along with reports. - enum CookiesPreference { SEND_COOKIES, DO_NOT_SEND_COOKIES }; - // Constructs a ReportSender that sends reports with the - // given |request_context| and includes or excludes cookies based on - // |cookies_preference|. |request_context| must outlive the - // ReportSender. - ReportSender(URLRequestContext* request_context, - CookiesPreference cookies_preference); + // given |request_context|, always excluding cookies. |request_context| must + // outlive the ReportSender. + explicit ReportSender(URLRequestContext* request_context); ~ReportSender() override; @@ -59,9 +54,6 @@ private: net::URLRequestContext* const request_context_; - - CookiesPreference cookies_preference_; - std::map<URLRequest*, std::unique_ptr<URLRequest>> inflight_requests_; DISALLOW_COPY_AND_ASSIGN(ReportSender);
diff --git a/net/url_request/report_sender_unittest.cc b/net/url_request/report_sender_unittest.cc index a4243cf..c4e8da4 100644 --- a/net/url_request/report_sender_unittest.cc +++ b/net/url_request/report_sender_unittest.cc
@@ -120,8 +120,7 @@ TestReportSenderNetworkDelegate() : url_request_destroyed_callback_(base::Bind(&base::DoNothing)), all_url_requests_destroyed_callback_(base::Bind(&base::DoNothing)), - num_requests_(0), - expect_cookies_(false) {} + num_requests_(0) {} void ExpectReport(const std::string& report) { expect_reports_.insert(report); @@ -139,11 +138,6 @@ size_t num_requests() const { return num_requests_; } - // Sets whether cookies are expected to be sent on requests. - void set_expect_cookies(bool expect_cookies) { - expect_cookies_ = expect_cookies; - } - void set_expected_content_type(const std::string& content_type) { expected_content_type_ = content_type; } @@ -155,14 +149,8 @@ num_requests_++; EXPECT_EQ(expect_url_, request->url()); EXPECT_STRCASEEQ("POST", request->method().data()); - - if (expect_cookies_) { - EXPECT_FALSE(request->load_flags() & LOAD_DO_NOT_SEND_COOKIES); - EXPECT_FALSE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES); - } else { - EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SEND_COOKIES); - EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES); - } + EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SEND_COOKIES); + EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES); const HttpRequestHeaders& extra_headers = request->extra_request_headers(); std::string content_type; @@ -189,7 +177,6 @@ size_t num_requests_; GURL expect_url_; std::set<std::string> expect_reports_; - bool expect_cookies_; std::string expected_content_type_; DISALLOW_COPY_AND_ASSIGN(TestReportSenderNetworkDelegate); @@ -263,13 +250,13 @@ // endpoint and sends the expected data. TEST_F(ReportSenderTest, SendsRequest) { GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); SendReport(&reporter, kDummyReport, url, 0); } TEST_F(ReportSenderTest, SendMultipleReportsSequentially) { GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); SendReport(&reporter, kDummyReport, url, 0); SendReport(&reporter, kDummyReport, url, 1); } @@ -285,7 +272,7 @@ network_delegate_.ExpectReport(kSecondDummyReport); network_delegate_.set_expected_content_type("application/foobar"); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); EXPECT_EQ(0u, network_delegate_.num_requests()); @@ -316,8 +303,7 @@ EXPECT_EQ(0u, network_delegate_.num_requests()); - std::unique_ptr<ReportSender> reporter( - new ReportSender(context(), ReportSender::DO_NOT_SEND_COOKIES)); + std::unique_ptr<ReportSender> reporter(new ReportSender(context())); reporter->Send(url, "application/foobar", kDummyReport, base::Callback<void()>(), base::Callback<void(const GURL&, int, int)>()); @@ -330,7 +316,7 @@ // Test that a request that returns an error gets cleaned up. TEST_F(ReportSenderTest, ErroredRequestGetsDeleted) { GURL url = URLRequestFailedJob::GetMockHttpsUrl(ERR_FAILED); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); // SendReport will block until the URLRequest is destroyed. SendReport(&reporter, kDummyReport, url, 0); } @@ -341,7 +327,7 @@ bool error_callback_called = false; bool success_callback_called = false; const GURL url = URLRequestFailedJob::GetMockHttpsUrl(ERR_FAILED); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); // SendReport will block until the URLRequest is destroyed. SendReport(&reporter, kDummyReport, url, 0, base::Bind(SuccessCallback, &success_callback_called), @@ -357,7 +343,7 @@ bool error_callback_called = false; bool success_callback_called = false; const GURL url(std::string("http://") + kServerErrorHostname); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); // SendReport will block until the URLRequest is destroyed. SendReport(&reporter, kDummyReport, url, 0, base::Bind(SuccessCallback, &success_callback_called), @@ -372,7 +358,7 @@ bool error_callback_called = false; bool success_callback_called = false; const GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); + ReportSender reporter(context()); SendReport(&reporter, kDummyReport, url, 0, base::Bind(SuccessCallback, &success_callback_called), base::Bind(ErrorCallback, &error_callback_called)); @@ -380,24 +366,5 @@ EXPECT_TRUE(success_callback_called); } -// Test that cookies are sent or not sent according to the error -// reporter's cookies preference. - -TEST_F(ReportSenderTest, SendCookiesPreference) { - GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1); - ReportSender reporter(context(), ReportSender::SEND_COOKIES); - - network_delegate_.set_expect_cookies(true); - SendReport(&reporter, kDummyReport, url, 0); -} - -TEST_F(ReportSenderTest, DoNotSendCookiesPreference) { - GURL url = URLRequestMockDataJob::GetMockHttpsUrl("dummy data", 1); - ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES); - - network_delegate_.set_expect_cookies(false); - SendReport(&reporter, kDummyReport, url, 0); -} - } // namespace } // namespace net
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc index 5856290..84bc3e3db 100644 --- a/remoting/host/it2me/it2me_host.cc +++ b/remoting/host/it2me/it2me_host.cc
@@ -174,11 +174,19 @@ } // Check the host domain policy. - if (!required_host_domain_.empty() && - !base::EndsWith(username_, std::string("@") + required_host_domain_, - base::CompareCase::INSENSITIVE_ASCII)) { - SetState(kInvalidDomainError, ""); - return; + if (!required_host_domain_list_.empty()) { + bool matched = false; + for (const auto& domain : required_host_domain_list_) { + if (base::EndsWith(username_, std::string("@") + domain, + base::CompareCase::INSENSITIVE_ASCII)) { + matched = true; + break; + } + } + if (!matched) { + SetState(kInvalidDomainError, ""); + return; + } } // Generate a key pair for the Host to use. @@ -314,14 +322,23 @@ &nat_policy)) { UpdateNatPolicy(nat_policy); } - std::string host_domain; - if (policies->GetString(policy::key::kRemoteAccessHostDomain, &host_domain)) { - UpdateHostDomainPolicy(host_domain); + const base::ListValue* host_domain_list; + if (policies->GetList(policy::key::kRemoteAccessHostDomainList, + &host_domain_list)) { + std::vector<std::string> host_domain_list_vector; + for (const auto& value : *host_domain_list) { + host_domain_list_vector.push_back(value.GetString()); + } + UpdateHostDomainListPolicy(std::move(host_domain_list_vector)); } - std::string client_domain; - if (policies->GetString(policy::key::kRemoteAccessHostClientDomain, - &client_domain)) { - UpdateClientDomainPolicy(client_domain); + const base::ListValue* client_domain_list; + if (policies->GetList(policy::key::kRemoteAccessHostClientDomainList, + &client_domain_list)) { + std::vector<std::string> client_domain_list_vector; + for (const auto& value : *client_domain_list) { + client_domain_list_vector.push_back(value.GetString()); + } + UpdateClientDomainListPolicy(std::move(client_domain_list_vector)); } policy_received_ = true; @@ -355,30 +372,34 @@ nat_traversal_enabled_)); } -void It2MeHost::UpdateHostDomainPolicy(const std::string& host_domain) { +void It2MeHost::UpdateHostDomainListPolicy( + std::vector<std::string> host_domain_list) { DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); - VLOG(2) << "UpdateHostDomainPolicy: " << host_domain; + VLOG(2) << "UpdateHostDomainListPolicy: " + << base::JoinString(host_domain_list, ", "); // When setting a host domain policy, force disconnect any existing session. - if (!host_domain.empty() && IsRunning()) { + if (!host_domain_list.empty() && IsRunning()) { DisconnectOnNetworkThread(); } - required_host_domain_ = host_domain; + required_host_domain_list_ = std::move(host_domain_list); } -void It2MeHost::UpdateClientDomainPolicy(const std::string& client_domain) { +void It2MeHost::UpdateClientDomainListPolicy( + std::vector<std::string> client_domain_list) { DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); - VLOG(2) << "UpdateClientDomainPolicy: " << client_domain; + VLOG(2) << "UpdateClientDomainPolicy: " + << base::JoinString(client_domain_list, ", "); // When setting a client domain policy, disconnect any existing session. - if (!client_domain.empty() && IsRunning()) { + if (!client_domain_list.empty() && IsRunning()) { DisconnectOnNetworkThread(); } - required_client_domain_ = client_domain; + required_client_domain_list_ = std::move(client_domain_list); } void It2MeHost::SetState(It2MeHostState state, @@ -502,12 +523,18 @@ } // Check the client domain policy. - if (!required_client_domain_.empty()) { - if (!base::EndsWith(client_username, - std::string("@") + required_client_domain_, - base::CompareCase::INSENSITIVE_ASCII)) { + if (!required_client_domain_list_.empty()) { + bool matched = false; + for (const auto& domain : required_client_domain_list_) { + if (base::EndsWith(client_username, std::string("@") + domain, + base::CompareCase::INSENSITIVE_ASCII)) { + matched = true; + break; + } + } + if (!matched) { LOG(ERROR) << "Rejecting incoming connection from " << remote_jid - << ": Domain mismatch."; + << ": Domain not allowed."; result_callback.Run(ValidationResult::ERROR_INVALID_ACCOUNT); DisconnectOnNetworkThread(); return;
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h index 76b6d034..95390c4 100644 --- a/remoting/host/it2me/it2me_host.h +++ b/remoting/host/it2me/it2me_host.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <vector> #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -137,8 +138,9 @@ // Handlers for NAT traversal and domain policies. void UpdateNatPolicy(bool nat_traversal_enabled); - void UpdateHostDomainPolicy(const std::string& host_domain); - void UpdateClientDomainPolicy(const std::string& client_domain); + void UpdateHostDomainListPolicy(std::vector<std::string> host_domain_list); + void UpdateClientDomainListPolicy( + std::vector<std::string> client_domain_list); void DisconnectOnNetworkThread(); @@ -174,8 +176,8 @@ bool nat_traversal_enabled_ = false; // The client and host domain policy setting. - std::string required_client_domain_; - std::string required_host_domain_; + std::vector<std::string> required_client_domain_list_; + std::vector<std::string> required_host_domain_list_; // Tracks the JID of the remote user when in a connecting state. std::string connecting_jid_;
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc index 38cafc4f..f307e6c 100644 --- a/remoting/host/it2me/it2me_host_unittest.cc +++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -354,6 +354,80 @@ ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); } +TEST_F(It2MeHostTest, HostValidation_HostDomainListPolicy_MatchFirst) { + base::ListValue domains; + domains.AppendString(kMatchingDomain); + domains.AppendString(kMismatchedDomain1); + SetPolicies({{policy::key::kRemoteAccessHostDomainList, domains}}); + StartHost(); + ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, HostValidation_HostDomainListPolicy_MatchSecond) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMatchingDomain); + SetPolicies({{policy::key::kRemoteAccessHostDomainList, domains}}); + StartHost(); + ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, HostValidation_HostDomainListPolicy_NoMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMismatchedDomain2); + SetPolicies({{policy::key::kRemoteAccessHostDomainList, domains}}); + StartHost(); + ASSERT_EQ(It2MeHostState::kInvalidDomainError, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, HostValidation_HostDomainBothPolicies_BothMatch) { + base::ListValue domains; + domains.AppendString(kMatchingDomain); + domains.AppendString(kMismatchedDomain1); + SetPolicies( + {{policy::key::kRemoteAccessHostDomain, base::Value(kMatchingDomain)}, + {policy::key::kRemoteAccessHostDomainList, domains}}); + StartHost(); + ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, HostValidation_HostDomainBothPolicies_ListMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMatchingDomain); + SetPolicies( + {{policy::key::kRemoteAccessHostDomain, base::Value(kMismatchedDomain1)}, + {policy::key::kRemoteAccessHostDomainList, domains}}); + // Should succeed even though the legacy policy would deny. + StartHost(); + ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, HostValidation_HostDomainBothPolicies_LegacyMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMismatchedDomain2); + SetPolicies( + {{policy::key::kRemoteAccessHostDomain, base::Value(kMatchingDomain)}, + {policy::key::kRemoteAccessHostDomainList, domains}}); + // Should fail even though the legacy policy would allow. + StartHost(); + ASSERT_EQ(It2MeHostState::kInvalidDomainError, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + TEST_F(It2MeHostTest, ConnectionValidation_NoClientDomainPolicy_ValidJid) { StartHost(); RunValidationCallback(kTestClientJid); @@ -451,6 +525,91 @@ ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); } +TEST_F(It2MeHostTest, ConnectionValidation_ClientDomainListPolicy_MatchFirst) { + base::ListValue domains; + domains.AppendString(kMatchingDomain); + domains.AppendString(kMismatchedDomain1); + SetPolicies({{policy::key::kRemoteAccessHostClientDomainList, domains}}); + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::SUCCESS, validation_result_); + ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, ConnectionValidation_ClientDomainListPolicy_MatchSecond) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMatchingDomain); + SetPolicies({{policy::key::kRemoteAccessHostClientDomainList, domains}}); + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::SUCCESS, validation_result_); + ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, ConnectionValidation_ClientDomainListPolicy_NoMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMismatchedDomain2); + SetPolicies({{policy::key::kRemoteAccessHostClientDomainList, domains}}); + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_); + RunUntilStateChanged(It2MeHostState::kDisconnected); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, ConnectionValidation_ClientDomainBothPolicies_BothMatch) { + base::ListValue domains; + domains.AppendString(kMatchingDomain); + domains.AppendString(kMismatchedDomain1); + SetPolicies({{policy::key::kRemoteAccessHostClientDomain, + base::Value(kMatchingDomain)}, + {policy::key::kRemoteAccessHostClientDomainList, domains}}); + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::SUCCESS, validation_result_); + ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, ConnectionValidation_ClientDomainBothPolicies_ListMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMatchingDomain); + SetPolicies({{policy::key::kRemoteAccessHostClientDomain, + base::Value(kMismatchedDomain1)}, + {policy::key::kRemoteAccessHostClientDomainList, domains}}); + // Should succeed even though the legacy policy would deny. + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::SUCCESS, validation_result_); + ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_); + ShutdownHost(); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + +TEST_F(It2MeHostTest, + ConnectionValidation_ClientDomainBothPolicies_LegacyMatch) { + base::ListValue domains; + domains.AppendString(kMismatchedDomain1); + domains.AppendString(kMismatchedDomain2); + SetPolicies({{policy::key::kRemoteAccessHostClientDomain, + base::Value(kMatchingDomain)}, + {policy::key::kRemoteAccessHostClientDomainList, domains}}); + // Should fail even though the legacy policy would allow. + StartHost(); + RunValidationCallback(kTestClientJid); + ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_); + RunUntilStateChanged(It2MeHostState::kDisconnected); + ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_); +} + TEST_F(It2MeHostTest, ConnectionValidation_ConfirmationDialog_Accept) { StartHost(); RunValidationCallback(kTestClientJid);
diff --git a/remoting/host/policy_watcher.cc b/remoting/host/policy_watcher.cc index 569e328..9bb9007 100644 --- a/remoting/host/policy_watcher.cc +++ b/remoting/host/policy_watcher.cc
@@ -181,8 +181,10 @@ default_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); default_values_->SetBoolean(key::kRemoteAccessHostRequireCurtain, false); default_values_->SetBoolean(key::kRemoteAccessHostMatchUsername, false); - default_values_->SetString(key::kRemoteAccessHostClientDomain, std::string()); - default_values_->SetString(key::kRemoteAccessHostDomain, std::string()); + default_values_->Set(key::kRemoteAccessHostClientDomainList, + base::MakeUnique<base::ListValue>()); + default_values_->Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); default_values_->SetString(key::kRemoteAccessHostTalkGadgetPrefix, kDefaultHostTalkGadgetPrefix); default_values_->SetString(key::kRemoteAccessHostTokenUrl, std::string()); @@ -232,6 +234,7 @@ LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path << ": " << error; } + HandleDeprecatedPolicies(policy_dict); return true; } else { LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; @@ -239,6 +242,37 @@ } } +void PolicyWatcher::HandleDeprecatedPolicies(base::DictionaryValue* dict) { + // RemoteAccessHostDomain + if (dict->HasKey(policy::key::kRemoteAccessHostDomain)) { + if (!dict->HasKey(policy::key::kRemoteAccessHostDomainList)) { + std::string domain; + dict->GetString(policy::key::kRemoteAccessHostDomain, &domain); + if (!domain.empty()) { + auto list = base::MakeUnique<base::ListValue>(); + list->AppendString(domain); + dict->Set(policy::key::kRemoteAccessHostDomainList, std::move(list)); + } + } + dict->Remove(policy::key::kRemoteAccessHostDomain, nullptr); + } + + // RemoteAccessHostClientDomain + if (dict->HasKey(policy::key::kRemoteAccessHostClientDomain)) { + if (!dict->HasKey(policy::key::kRemoteAccessHostClientDomainList)) { + std::string domain; + dict->GetString(policy::key::kRemoteAccessHostClientDomain, &domain); + if (!domain.empty()) { + auto list = base::MakeUnique<base::ListValue>(); + list->AppendString(domain); + dict->Set(policy::key::kRemoteAccessHostClientDomainList, + std::move(list)); + } + } + dict->Remove(policy::key::kRemoteAccessHostClientDomain, nullptr); + } +} + namespace { void CopyDictionaryValue(const base::DictionaryValue& from, base::DictionaryValue& to,
diff --git a/remoting/host/policy_watcher.h b/remoting/host/policy_watcher.h index 5523b84..44f3863 100644 --- a/remoting/host/policy_watcher.h +++ b/remoting/host/policy_watcher.h
@@ -92,12 +92,18 @@ // Gets Chromoting schema stored inside |owned_schema_registry_|. const policy::Schema* GetPolicySchema() const; - // Simplifying wrapper around Schema::Normalize. + // Normalizes policies using Schema::Normalize and converts deprecated + // policies. + // // - Returns false if |dict| is invalid (i.e. contains mistyped policy // values). // - Returns true if |dict| was valid or got normalized. bool NormalizePolicies(base::DictionaryValue* dict); + // Converts each deprecated policy to its replacement if and only if the + // replacement policy is not set, and removes deprecated policied from dict. + void HandleDeprecatedPolicies(base::DictionaryValue* dict); + // Stores |new_policies| into |old_policies_|. Returns dictionary with items // from |new_policies| that are different from the old |old_policies_|. std::unique_ptr<base::DictionaryValue> StoreNewAndReturnChangedPolicies(
diff --git a/remoting/host/policy_watcher_unittest.cc b/remoting/host/policy_watcher_unittest.cc index ccbdf6d..4b70a6a 100644 --- a/remoting/host/policy_watcher_unittest.cc +++ b/remoting/host/policy_watcher_unittest.cc
@@ -74,13 +74,29 @@ policy_watcher_ = PolicyWatcher::CreateFromPolicyLoaderForTesting( base::WrapUnique(policy_loader_)); + base::ListValue host_domain; + host_domain.AppendString(kHostDomain); + base::ListValue client_domain; + client_domain.AppendString(kClientDomain); + base::ListValue multiple_host_domains; + multiple_host_domains.AppendString("a.com"); + multiple_host_domains.AppendString("b.com"); + multiple_host_domains.AppendString("c.com"); + base::ListValue multiple_client_domains; + multiple_client_domains.AppendString("d.com"); + multiple_client_domains.AppendString("e.com"); + multiple_client_domains.AppendString("f.com"); + nat_true_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); nat_false_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, false); nat_one_.SetInteger(key::kRemoteAccessHostFirewallTraversal, 1); nat_one_domain_full_.SetInteger(key::kRemoteAccessHostFirewallTraversal, 1); - nat_one_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); - domain_empty_.SetString(key::kRemoteAccessHostDomain, std::string()); - domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + nat_one_domain_full_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); + domain_empty_.Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); + domain_full_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); SetDefaults(nat_true_others_default_); nat_true_others_default_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); @@ -88,30 +104,32 @@ nat_false_others_default_.SetBoolean( key::kRemoteAccessHostFirewallTraversal, false); SetDefaults(domain_empty_others_default_); - domain_empty_others_default_.SetString(key::kRemoteAccessHostDomain, - std::string()); + domain_empty_others_default_.Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); SetDefaults(domain_full_others_default_); - domain_full_others_default_.SetString(key::kRemoteAccessHostDomain, - kHostDomain); + domain_full_others_default_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); nat_true_domain_empty_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); - nat_true_domain_empty_.SetString(key::kRemoteAccessHostDomain, - std::string()); + nat_true_domain_empty_.Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); nat_true_domain_full_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); - nat_true_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + nat_true_domain_full_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); nat_false_domain_empty_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, false); - nat_false_domain_empty_.SetString(key::kRemoteAccessHostDomain, - std::string()); + nat_false_domain_empty_.Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); nat_false_domain_full_.SetBoolean(key::kRemoteAccessHostFirewallTraversal, false); - nat_false_domain_full_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + nat_false_domain_full_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); SetDefaults(nat_true_domain_empty_others_default_); nat_true_domain_empty_others_default_.SetBoolean( key::kRemoteAccessHostFirewallTraversal, true); - nat_true_domain_empty_others_default_.SetString( - key::kRemoteAccessHostDomain, std::string()); + nat_true_domain_empty_others_default_.Set( + key::kRemoteAccessHostDomainList, base::MakeUnique<base::ListValue>()); unknown_policies_.SetString("UnknownPolicyOne", std::string()); unknown_policies_.SetString("UnknownPolicyTwo", std::string()); unknown_policies_.SetBoolean("RemoteAccessHostUnknownPolicyThree", true); @@ -129,8 +147,8 @@ port_range_malformed_.SetString(key::kRemoteAccessHostUdpPortRange, "malformed"); port_range_malformed_domain_full_.MergeDictionary(&port_range_malformed_); - port_range_malformed_domain_full_.SetString(key::kRemoteAccessHostDomain, - kHostDomain); + port_range_malformed_domain_full_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); curtain_true_.SetBoolean(key::kRemoteAccessHostRequireCurtain, true); curtain_false_.SetBoolean(key::kRemoteAccessHostRequireCurtain, false); @@ -152,6 +170,37 @@ key::kRemoteAccessHostAllowUiAccessForRemoteAssistance, true); remote_assistance_uiaccess_false_.SetBoolean( key::kRemoteAccessHostAllowUiAccessForRemoteAssistance, false); + + deprecated_policies_.SetString(key::kRemoteAccessHostDomain, kHostDomain); + deprecated_policies_.SetString(key::kRemoteAccessHostClientDomain, + kClientDomain); + // Deprecated policies should get converted if new ones aren't present. + SetDefaults(deprecated_policies_expected_); + deprecated_policies_expected_.Set(key::kRemoteAccessHostDomainList, + host_domain.CreateDeepCopy()); + deprecated_policies_expected_.Set(key::kRemoteAccessHostClientDomainList, + client_domain.CreateDeepCopy()); + + deprecated_and_new_policies_.SetString(key::kRemoteAccessHostDomain, + kHostDomain); + deprecated_and_new_policies_.SetString(key::kRemoteAccessHostClientDomain, + kClientDomain); + deprecated_and_new_policies_.Set(key::kRemoteAccessHostDomainList, + multiple_host_domains.CreateDeepCopy()); + deprecated_and_new_policies_.Set(key::kRemoteAccessHostClientDomainList, + multiple_client_domains.CreateDeepCopy()); + // Deprecated policies should just be dropped in new ones are present. + SetDefaults(deprecated_and_new_policies_expected_); + deprecated_and_new_policies_expected_.Set( + key::kRemoteAccessHostDomainList, + multiple_host_domains.CreateDeepCopy()); + deprecated_and_new_policies_expected_.Set( + key::kRemoteAccessHostClientDomainList, + multiple_client_domains.CreateDeepCopy()); + + // Empty strings should be treated as not set. + deprecated_empty_strings_.SetString(key::kRemoteAccessHostDomain, ""); + deprecated_empty_strings_.SetString(key::kRemoteAccessHostClientDomain, ""); } void TearDown() override { @@ -197,6 +246,7 @@ MOCK_METHOD0(PostPolicyWatcherShutdown, void()); static const char* kHostDomain; + static const char* kClientDomain; static const char* kPortRange; base::MessageLoop message_loop_; MockPolicyCallback mock_policy_callback_; @@ -244,14 +294,21 @@ base::DictionaryValue third_party_auth_cert_empty_; base::DictionaryValue remote_assistance_uiaccess_true_; base::DictionaryValue remote_assistance_uiaccess_false_; + base::DictionaryValue deprecated_policies_; + base::DictionaryValue deprecated_policies_expected_; + base::DictionaryValue deprecated_and_new_policies_; + base::DictionaryValue deprecated_and_new_policies_expected_; + base::DictionaryValue deprecated_empty_strings_; private: void SetDefaults(base::DictionaryValue& dict) { dict.SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); dict.SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, true); dict.SetString(key::kRemoteAccessHostUdpPortRange, ""); - dict.SetString(key::kRemoteAccessHostClientDomain, std::string()); - dict.SetString(key::kRemoteAccessHostDomain, std::string()); + dict.Set(key::kRemoteAccessHostClientDomainList, + base::MakeUnique<base::ListValue>()); + dict.Set(key::kRemoteAccessHostDomainList, + base::MakeUnique<base::ListValue>()); dict.SetBoolean(key::kRemoteAccessHostMatchUsername, false); dict.SetString(key::kRemoteAccessHostTalkGadgetPrefix, kDefaultHostTalkGadgetPrefix); @@ -271,6 +328,7 @@ }; const char* PolicyWatcherTest::kHostDomain = "google.com"; +const char* PolicyWatcherTest::kClientDomain = "client.com"; const char* PolicyWatcherTest::kPortRange = "12400-12409"; TEST_F(PolicyWatcherTest, None) { @@ -659,6 +717,11 @@ // policies, so we have to skip them here. continue; } + if (key == policy::key::kRemoteAccessHostDomain || + key == policy::key::kRemoteAccessHostClientDomain) { + // These policies are deprecated and get removed during normalization + continue; + } actual_schema[key] = it.schema().type(); } @@ -684,4 +747,26 @@ EXPECT_EQ(boolean_schema.type(), base::Value::Type::BOOLEAN); } +TEST_F(PolicyWatcherTest, DeprecatedOnly) { + EXPECT_CALL(mock_policy_callback_, + OnPolicyUpdatePtr(IsPolicies(&deprecated_policies_expected_))); + SetPolicies(deprecated_policies_); + StartWatching(); +} + +TEST_F(PolicyWatcherTest, DeprecatedAndNew) { + EXPECT_CALL( + mock_policy_callback_, + OnPolicyUpdatePtr(IsPolicies(&deprecated_and_new_policies_expected_))); + SetPolicies(deprecated_and_new_policies_); + StartWatching(); +} + +TEST_F(PolicyWatcherTest, DeprecatedEmpty) { + EXPECT_CALL(mock_policy_callback_, + OnPolicyUpdatePtr(IsPolicies(&GetDefaultValues()))); + SetPolicies(deprecated_empty_strings_); + StartWatching(); +} + } // namespace remoting
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index cf21b6cc..018d1c8 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -10,6 +10,7 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "base/bind.h" #include "base/callback.h" @@ -294,10 +295,10 @@ void OnPolicyUpdate(std::unique_ptr<base::DictionaryValue> policies); void OnPolicyError(); void ReportPolicyErrorAndRestartHost(); - void ApplyHostDomainPolicy(); + void ApplyHostDomainListPolicy(); void ApplyUsernamePolicy(); - bool OnClientDomainPolicyUpdate(base::DictionaryValue* policies); - bool OnHostDomainPolicyUpdate(base::DictionaryValue* policies); + bool OnClientDomainListPolicyUpdate(base::DictionaryValue* policies); + bool OnHostDomainListPolicyUpdate(base::DictionaryValue* policies); bool OnUsernamePolicyUpdate(base::DictionaryValue* policies); bool OnNatPolicyUpdate(base::DictionaryValue* policies); bool OnRelayPolicyUpdate(base::DictionaryValue* policies); @@ -375,8 +376,8 @@ std::unique_ptr<PolicyWatcher> policy_watcher_; PolicyState policy_state_ = POLICY_INITIALIZING; - std::string client_domain_; - std::string host_domain_; + std::vector<std::string> client_domain_list_; + std::vector<std::string> host_domain_list_; bool host_username_match_required_ = false; bool allow_nat_traversal_ = true; bool allow_relay_ = true; @@ -591,7 +592,7 @@ } else if (state_ == HOST_STARTED) { // Reapply policies that could be affected by a new config. DCHECK_EQ(policy_state_, POLICY_LOADED); - ApplyHostDomainPolicy(); + ApplyHostDomainListPolicy(); ApplyUsernamePolicy(); // TODO(sergeyu): Here we assume that PIN is the only part of the config @@ -724,7 +725,7 @@ factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithPin( use_service_account_, host_owner_, local_certificate, key_pair_, - client_domain_, pin_hash_, pairing_registry); + client_domain_list_, pin_hash_, pairing_registry); host_->set_pairing_registry(pairing_registry); } else { @@ -748,7 +749,7 @@ context_->url_request_context_getter()); factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( use_service_account_, host_owner_, local_certificate, key_pair_, - client_domain_, token_validator_factory); + client_domain_list_, token_validator_factory); } #if defined(OS_POSIX) @@ -1019,8 +1020,8 @@ } bool restart_required = false; - restart_required |= OnClientDomainPolicyUpdate(policies.get()); - restart_required |= OnHostDomainPolicyUpdate(policies.get()); + restart_required |= OnClientDomainListPolicyUpdate(policies.get()); + restart_required |= OnHostDomainListPolicyUpdate(policies.get()); restart_required |= OnCurtainPolicyUpdate(policies.get()); // Note: UsernamePolicyUpdate must run after OnCurtainPolicyUpdate. restart_required |= OnUsernamePolicyUpdate(policies.get()); @@ -1069,13 +1070,14 @@ RestartHost(kHostOfflineReasonPolicyReadError); } -void HostProcess::ApplyHostDomainPolicy() { +void HostProcess::ApplyHostDomainListPolicy() { if (state_ != HOST_STARTED) return; - HOST_LOG << "Policy sets host domain: " << host_domain_; + HOST_LOG << "Policy sets host domains: " + << base::JoinString(host_domain_list_, ", "); - if (!host_domain_.empty()) { + if (!host_domain_list_.empty()) { // If the user does not have a Google email, their client JID will not be // based on their email. In that case, the username/host domain policies // would be meaningless, since there is no way to check that the JID @@ -1086,32 +1088,55 @@ ShutdownHost(kInvalidHostDomainExitCode); } - if (!base::EndsWith(host_owner_, std::string("@") + host_domain_, - base::CompareCase::INSENSITIVE_ASCII)) { + bool matched = false; + for (const std::string& domain : host_domain_list_) { + if (base::EndsWith(host_owner_, std::string("@") + domain, + base::CompareCase::INSENSITIVE_ASCII)) { + matched = true; + } + } + if (!matched) { LOG(ERROR) << "The host domain does not match the policy."; ShutdownHost(kInvalidHostDomainExitCode); } } } -bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) { +bool HostProcess::OnHostDomainListPolicyUpdate( + base::DictionaryValue* policies) { // Returns true if the host has to be restarted after this policy update. DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - if (!policies->GetString(policy::key::kRemoteAccessHostDomain, - &host_domain_)) { + const base::ListValue* list; + if (!policies->GetList(policy::key::kRemoteAccessHostDomainList, &list)) { return false; } - ApplyHostDomainPolicy(); + host_domain_list_.clear(); + for (const auto& value : *list) { + host_domain_list_.push_back(value.GetString()); + } + + ApplyHostDomainListPolicy(); return false; } -bool HostProcess::OnClientDomainPolicyUpdate(base::DictionaryValue* policies) { +bool HostProcess::OnClientDomainListPolicyUpdate( + base::DictionaryValue* policies) { // Returns true if the host has to be restarted after this policy update. DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - return policies->GetString(policy::key::kRemoteAccessHostClientDomain, - &client_domain_); + const base::ListValue* list; + if (!policies->GetList(policy::key::kRemoteAccessHostClientDomainList, + &list)) { + return false; + } + + client_domain_list_.clear(); + for (const auto& value : *list) { + client_domain_list_.push_back(value.GetString()); + } + + return true; } void HostProcess::ApplyUsernamePolicy() { @@ -1121,7 +1146,7 @@ if (host_username_match_required_) { HOST_LOG << "Policy requires host username match."; - // See comment in ApplyHostDomainPolicy. + // See comment in ApplyHostDomainListPolicy. if (host_owner_ != host_owner_email_) { LOG(ERROR) << "The username and host domain policies cannot be enabled " << "for accounts with a non-Google email."; @@ -1496,7 +1521,7 @@ CreateAuthenticatorFactory(); - ApplyHostDomainPolicy(); + ApplyHostDomainListPolicy(); ApplyUsernamePolicy(); }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc index 6e63fbe..37c627b 100644 --- a/remoting/protocol/me2me_host_authenticator_factory.cc +++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -27,7 +27,7 @@ const std::string& host_owner, const std::string& local_cert, scoped_refptr<RsaKeyPair> key_pair, - const std::string& required_client_domain, + std::vector<std::string> required_client_domain_list, const std::string& pin_hash, scoped_refptr<PairingRegistry> pairing_registry) { std::unique_ptr<Me2MeHostAuthenticatorFactory> result( @@ -36,7 +36,7 @@ result->host_owner_ = host_owner; result->local_cert_ = local_cert; result->key_pair_ = key_pair; - result->required_client_domain_ = required_client_domain; + result->required_client_domain_list_ = std::move(required_client_domain_list); result->pin_hash_ = pin_hash; result->pairing_registry_ = pairing_registry; return std::move(result); @@ -50,7 +50,7 @@ const std::string& host_owner, const std::string& local_cert, scoped_refptr<RsaKeyPair> key_pair, - const std::string& required_client_domain, + std::vector<std::string> required_client_domain_list, scoped_refptr<TokenValidatorFactory> token_validator_factory) { std::unique_ptr<Me2MeHostAuthenticatorFactory> result( new Me2MeHostAuthenticatorFactory()); @@ -58,7 +58,7 @@ result->host_owner_ = host_owner; result->local_cert_ = local_cert; result->key_pair_ = key_pair; - result->required_client_domain_ = required_client_domain; + result->required_client_domain_list_ = std::move(required_client_domain_list); result->token_validator_factory_ = token_validator_factory; return std::move(result); } @@ -101,19 +101,25 @@ } // If necessary, verify that the client's jid belongs to the correct domain. - if (!required_client_domain_.empty()) { + if (!required_client_domain_list_.empty()) { std::string client_username = remote_jid; size_t pos = client_username.find('/'); if (pos != std::string::npos) { client_username.replace(pos, std::string::npos, ""); } - if (!base::EndsWith(client_username, - std::string("@") + required_client_domain_, - base::CompareCase::INSENSITIVE_ASCII)) { + bool matched = false; + for (const std::string& domain : required_client_domain_list_) { + if (base::EndsWith(client_username, std::string("@") + domain, + base::CompareCase::INSENSITIVE_ASCII)) { + matched = true; + break; + } + } + if (!matched) { LOG(ERROR) << "Rejecting incoming connection from " << remote_jid - << ": Domain mismatch."; - return base::WrapUnique( - new RejectingAuthenticator(Authenticator::INVALID_ACCOUNT)); + << ": Domain not allowed."; + return base::MakeUnique<RejectingAuthenticator>( + Authenticator::INVALID_ACCOUNT); } }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.h b/remoting/protocol/me2me_host_authenticator_factory.h index e081ba8..8a9ad782 100644 --- a/remoting/protocol/me2me_host_authenticator_factory.h +++ b/remoting/protocol/me2me_host_authenticator_factory.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <vector> #include "base/compiler_specific.h" #include "base/macros.h" @@ -31,7 +32,7 @@ const std::string& host_owner, const std::string& local_cert, scoped_refptr<RsaKeyPair> key_pair, - const std::string& required_client_domain, + std::vector<std::string> required_client_domain_list, const std::string& pin_hash, scoped_refptr<PairingRegistry> pairing_registry); @@ -41,7 +42,7 @@ const std::string& host_owner, const std::string& local_cert, scoped_refptr<RsaKeyPair> key_pair, - const std::string& required_client_domain, + std::vector<std::string> required_client_domain_list, scoped_refptr<TokenValidatorFactory> token_validator_factory); Me2MeHostAuthenticatorFactory(); @@ -58,7 +59,7 @@ std::string host_owner_; std::string local_cert_; scoped_refptr<RsaKeyPair> key_pair_; - std::string required_client_domain_; + std::vector<std::string> required_client_domain_list_; // Used only for PIN-based host authenticators. std::string pin_hash_;
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd index 0c7ee57d..7139649 100644 --- a/remoting/resources/remoting_strings.grd +++ b/remoting/resources/remoting_strings.grd
@@ -962,7 +962,7 @@ name="IDS_OFFLINE_REASON_INVALID_OAUTH_CREDENTIALS" formatter_data="android_java"> Host is configured with invalid OAuth credentials. </message> - <message desc="Error message indicating that the host is offline, because the host is owned by a user from a domain different than the domain mandated by RemoteAccessHostDomain policy." + <message desc="Error message indicating that the host is offline, because the host is owned by a user from a domain different than the domain mandated by RemoteAccessHostDomainList policy." name="IDS_OFFLINE_REASON_INVALID_HOST_DOMAIN" formatter_data="android_java"> Invalid host owner domain. </message>
diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc index 202b4e3..629ce8c 100644 --- a/remoting/test/protocol_perftest.cc +++ b/remoting/test/protocol_perftest.cc
@@ -311,7 +311,8 @@ protocol::GetSharedSecretHash(kHostId, kHostPin); std::unique_ptr<protocol::AuthenticatorFactory> auth_factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithPin( - true, kHostOwner, host_cert, key_pair, "", host_pin_hash, nullptr); + true, kHostOwner, host_cert, key_pair, std::vector<std::string>(), + host_pin_hash, nullptr); host_->SetAuthenticatorFactory(std::move(auth_factory)); host_->AddStatusObserver(this);
diff --git a/services/ui/display/screen_manager_forwarding.cc b/services/ui/display/screen_manager_forwarding.cc index 9ea9098..2ee16f2a 100644 --- a/services/ui/display/screen_manager_forwarding.cc +++ b/services/ui/display/screen_manager_forwarding.cc
@@ -37,11 +37,14 @@ } // namespace ScreenManagerForwarding::ScreenManagerForwarding() - : screen_(base::MakeUnique<display::ScreenBase>()), binding_(this) {} + : screen_(base::MakeUnique<display::ScreenBase>()), binding_(this) { + Screen::SetScreenInstance(screen_.get()); +} ScreenManagerForwarding::~ScreenManagerForwarding() { if (native_display_delegate_) native_display_delegate_->RemoveObserver(this); + Screen::SetScreenInstance(nullptr); } void ScreenManagerForwarding::AddInterfaces(
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index f48149ee5..c1fff16 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -31,6 +31,33 @@ namespace ui { namespace ws { +namespace { + +// Returns true if |window| is considered the active window manager for +// |display|. +bool IsWindowConsideredWindowManagerRoot(const Display* display, + const ServerWindow* window) { + if (!display) + return false; + + const WindowManagerDisplayRoot* display_root = + display->GetActiveWindowManagerDisplayRoot(); + if (!display_root) + return false; + + if (window == display_root->root()) + return true; + + // If the window manager manually creates displays then there is an extra + // window, the window supplied via SetDisplayRoot(). + return !display_root->window_manager_state() + ->window_tree() + ->automatically_create_display_roots() && + window->parent() == display_root->root(); +} + +} // namespace + struct WindowServer::CurrentMoveLoopState { uint32_t change_id; ServerWindow* window; @@ -824,8 +851,8 @@ if (!window_paint_callback_.is_null()) window_paint_callback_.Run(window); - auto* display = display_manager_->GetDisplayContaining(window); - if (display && window == display->GetActiveRootWindow()) { + Display* display = display_manager_->GetDisplayContaining(window); + if (IsWindowConsideredWindowManagerRoot(display, window)) { // A new surface for a WindowManager root has been created. This is a // special case because ServerWindows created by the WindowServer are not // part of a WindowTree. Send the SurfaceId directly to FrameGenerator and
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc index 086fd81..511a495c 100644 --- a/services/ui/ws/window_tree.cc +++ b/services/ui/ws/window_tree.cc
@@ -384,7 +384,7 @@ DVLOG(3) << "new window client=" << id_ << " window_id=" << client_window_id.id; if (!IsValidIdForNewWindow(client_window_id)) { - DVLOG(1) << "new window failed, id is not valid for client"; + DVLOG(1) << "NewWindow failed (id is not valid for client)"; return false; } const WindowId window_id = GenerateNewWindowId(); @@ -408,23 +408,23 @@ << " client child window_id= " << child_id.id << " global window_id=" << (child ? WindowIdToTransportId(child->id()) : 0); if (!parent) { - DVLOG(1) << "add failed, no parent"; + DVLOG(1) << "AddWindow failed (no parent)"; return false; } if (!child) { - DVLOG(1) << "add failed, no child"; + DVLOG(1) << "AddWindow failed (no child)"; return false; } if (child->parent() == parent) { - DVLOG(1) << "add failed, already has parent"; + DVLOG(1) << "AddWindow failed (already has parent)"; return false; } if (child->Contains(parent)) { - DVLOG(1) << "add failed, child contains parent"; + DVLOG(1) << "AddWindow failed (child contains parent)"; return false; } if (!access_policy_->CanAddWindow(parent, child)) { - DVLOG(1) << "add failed, access policy denied add"; + DVLOG(1) << "AddWindow failed (access denied)"; return false; } Operation op(this, window_server_, OperationType::ADD_WINDOW); @@ -539,11 +539,11 @@ << " client window_id= " << window_id.id << " global window_id=" << (window ? WindowIdToTransportId(window->id()) : 0); if (!window) { - DVLOG(1) << "SetWindowVisibility failure, no window"; + DVLOG(1) << "SetWindowVisibility failed (no window)"; return false; } if (!access_policy_->CanChangeWindowVisibility(window)) { - DVLOG(1) << "SetWindowVisibility failure, access policy denied change"; + DVLOG(1) << "SetWindowVisibility failed (access policy denied change)"; return false; } if (window->visible() == visible) @@ -569,25 +569,25 @@ ServerWindow* window = GetWindowByClientId(window_id); ServerWindow* currently_focused = window_server_->GetFocusedWindow(); if (!currently_focused && !window) { - DVLOG(1) << "SetFocus failure, no focused window to clear."; + DVLOG(1) << "SetFocus failed (no focused window to clear)"; return false; } Display* display = GetDisplay(window); if (window && (!display || !window->can_focus() || !window->IsDrawn())) { - DVLOG(1) << "SetFocus failure, window cannot be focused."; + DVLOG(1) << "SetFocus failed (window cannot be focused)"; return false; } if (!access_policy_->CanSetFocus(window)) { - DVLOG(1) << "SetFocus failure, blocked by access policy."; + DVLOG(1) << "SetFocus failed (blocked by access policy)"; return false; } Operation op(this, window_server_, OperationType::SET_FOCUS); bool success = window_server_->SetFocusedWindow(window); if (!success) { - DVLOG(1) << "SetFocus failure, could not SetFocusedWindow."; + DVLOG(1) << "SetFocus failed (could not SetFocusedWindow)"; } return success; } @@ -670,12 +670,14 @@ ServerWindow* window = GetWindowByClientId(window_id); if (window) { Display* display = GetDisplay(window); - if (display) + if (display) { display->AddActivationParent(window); - else - DVLOG(1) << "AddActivationParent window not associated with display"; + } else { + DVLOG(1) << "AddActivationParent failed " + << "(window not associated with display)"; + } } else { - DVLOG(1) << "AddActivationParent supplied invalid window id"; + DVLOG(1) << "AddActivationParent failed (invalid window id)"; } } @@ -1047,26 +1049,26 @@ const ServerWindow* relative_window, mojom::OrderDirection direction) const { if (!window) { - DVLOG(1) << "reorder failing: invalid window"; + DVLOG(1) << "CanReorderWindow failed (invalid window)"; return false; } if (!relative_window) { - DVLOG(1) << "reorder failing: invalid relative window"; + DVLOG(1) << "CanReorderWindow failed (invalid relative window)"; return false; } if (!window->parent()) { - DVLOG(1) << "reorder failing: no parent"; + DVLOG(1) << "CanReorderWindow failed (no parent)"; return false; } if (window->parent() != relative_window->parent()) { - DVLOG(1) << "reorder failing: parents differ"; + DVLOG(1) << "CanReorderWindow failed (parents differ)"; return false; } if (!access_policy_->CanReorderWindow(window, relative_window, direction)) { - DVLOG(1) << "reorder failing: access policy denied"; + DVLOG(1) << "CanReorderWindow failed (access policy denied)"; return false; } @@ -1078,7 +1080,7 @@ children.begin(); if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) || (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) { - DVLOG(1) << "reorder failing: already in position"; + DVLOG(1) << "CanReorderWindow failed (already in position)"; return false; } @@ -1424,11 +1426,14 @@ << " client window_id= " << window_id << " global window_id=" << (window ? WindowIdToTransportId(window->id()) : 0); if (!window) { - DVLOG(1) << "remove failing, invalid window id=" << change_id; + DVLOG(1) << "RemoveWindowFromParent failed (invalid window id=" << change_id + << ")"; } else if (!window->parent()) { - DVLOG(1) << "remove failing, no parent id=" << change_id; + DVLOG(1) << "RemoveWindowFromParent failed (no parent id=" << change_id + << ")"; } else if (!access_policy_->CanRemoveWindowFromParent(window)) { - DVLOG(1) << "remove failing, access policy disallowed id=" << change_id; + DVLOG(1) << "RemoveWindowFromParent failed (access policy disallowed id=" + << change_id << ")"; } else { success = true; Operation op(this, window_server_, @@ -1550,13 +1555,20 @@ << " global window_id=" << (window ? WindowIdToTransportId(window->id()) : 0) << " bounds=" << bounds.ToString(); + + if (!window) { + DVLOG(1) << "SetWindowBounds failed (invalid window id)"; + client()->OnChangeCompleted(change_id, false); + return; + } + // Only the owner of the window can change the bounds. - bool success = window && access_policy_->CanSetWindowBounds(window); + bool success = access_policy_->CanSetWindowBounds(window); if (success) { Operation op(this, window_server_, OperationType::SET_WINDOW_BOUNDS); window->SetBounds(bounds, local_surface_id); } else { - DVLOG(1) << "Failed to set bounds on window."; + DVLOG(1) << "SetWindowBounds failed (access denied)"; } client()->OnChangeCompleted(change_id, success); } @@ -1611,10 +1623,14 @@ cc::mojom::MojoCompositorFrameSinkClientPtr client) { ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); - const bool success = - window && access_policy_->CanSetWindowCompositorFrameSink(window); + if (!window) { + DVLOG(1) << "AttachCompositorFrameSink failed (invalid window id)"; + return; + } + + const bool success = access_policy_->CanSetWindowCompositorFrameSink(window); if (!success) { - DVLOG(1) << "request to AttachCompositorFrameSink failed"; + DVLOG(1) << "AttachCompositorFrameSink failed (access denied)"; return; } window->CreateCompositorFrameSink(std::move(compositor_frame_sink), @@ -1695,11 +1711,11 @@ << " insets=" << insets.top() << " " << insets.left() << " " << insets.bottom() << " " << insets.right(); if (!window) { - DVLOG(1) << "SetClientArea failed, no window"; + DVLOG(1) << "SetClientArea failed (invalid window id)"; return; } if (!access_policy_->CanSetClientArea(window)) { - DVLOG(1) << "SetClientArea failed, access denied"; + DVLOG(1) << "SetClientArea failed (access denied)"; return; } @@ -1712,8 +1728,13 @@ const base::Optional<gfx::Rect>& mask) { ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); - if (!window || !access_policy_->CanSetHitTestMask(window)) { - DVLOG(1) << "SetHitTestMask failed"; + if (!window) { + DVLOG(1) << "SetHitTestMask failed (invalid window id)"; + return; + } + + if (!access_policy_->CanSetHitTestMask(window)) { + DVLOG(1) << "SetHitTestMask failed (access denied)"; return; } @@ -1725,8 +1746,13 @@ void WindowTree::SetCanAcceptDrops(Id window_id, bool accepts_drops) { ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); - if (!window || !access_policy_->CanSetAcceptDrops(window)) { - DVLOG(1) << "SetAcceptsDrops failed"; + if (!window) { + DVLOG(1) << "SetCanAcceptDrops failed (invalid window id)"; + return; + } + + if (!access_policy_->CanSetAcceptDrops(window)) { + DVLOG(1) << "SetAcceptsDrops failed (access denied)"; return; } @@ -1750,7 +1776,7 @@ ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); if (!window) { - DVLOG(1) << "SetCanFocus failed (invalid id)"; + DVLOG(1) << "SetCanFocus failed (invalid window id)"; return; } @@ -1762,6 +1788,8 @@ can_focus); } else if (access_policy_->CanSetFocus(window)) { window->set_can_focus(can_focus); + } else { + DVLOG(1) << "SetCanFocus failed (access denied)"; } } @@ -1975,7 +2003,7 @@ if (!success || !ShouldRouteToWindowManager(window)) { // We need to fail this move loop change, otherwise the client will just be // waiting for |change_id|. - DVLOG(1) << "PerformDragDrop failed (access denied)."; + DVLOG(1) << "PerformDragDrop failed (access denied)"; client()->OnPerformDragDropCompleted(change_id, false, mojom::kDropEffectNone); return; @@ -1984,7 +2012,7 @@ WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window); if (!display_root) { // The window isn't parented. There's nothing to do. - DVLOG(1) << "PerformDragDrop failed (window unparented)."; + DVLOG(1) << "PerformDragDrop failed (window unparented)"; client()->OnPerformDragDropCompleted(change_id, false, mojom::kDropEffectNone); return; @@ -1993,7 +2021,7 @@ if (window_server_->in_move_loop() || window_server_->in_drag_loop()) { // Either the window manager is servicing a window drag or we're servicing // a drag and drop operation. We can't start a second drag. - DVLOG(1) << "PerformDragDrop failed (already performing a drag)."; + DVLOG(1) << "PerformDragDrop failed (already performing a drag)"; client()->OnPerformDragDropCompleted(change_id, false, mojom::kDropEffectNone); return; @@ -2048,7 +2076,7 @@ if (!success || !ShouldRouteToWindowManager(window)) { // We need to fail this move loop change, otherwise the client will just be // waiting for |change_id|. - DVLOG(1) << "PerformWindowMove failed (access denied)."; + DVLOG(1) << "PerformWindowMove failed (access denied)"; OnChangeCompleted(change_id, false); return; } @@ -2056,7 +2084,7 @@ WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window); if (!display_root) { // The window isn't parented. There's nothing to do. - DVLOG(1) << "PerformWindowMove failed (window unparented)."; + DVLOG(1) << "PerformWindowMove failed (window unparented)"; OnChangeCompleted(change_id, false); return; } @@ -2064,7 +2092,7 @@ if (window_server_->in_move_loop() || window_server_->in_drag_loop()) { // Either the window manager is servicing a window drag or we're servicing // a drag and drop operation. We can't start a second drag. - DVLOG(1) << "PerformWindowMove failed (already performing a drag)."; + DVLOG(1) << "PerformWindowMove failed (already performing a drag)"; OnChangeCompleted(change_id, false); return; } @@ -2087,9 +2115,14 @@ void WindowTree::CancelWindowMove(Id window_id) { ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); - bool success = window && access_policy_->CanInitiateMoveLoop(window); + if (!window) { + DVLOG(1) << "CancelWindowMove failed (invalid window id)"; + return; + } + + bool success = access_policy_->CanInitiateMoveLoop(window); if (!success) { - DVLOG(1) << "CancelWindowMove failed (no window / access denied)"; + DVLOG(1) << "CancelWindowMove failed (access denied)"; return; } @@ -2139,15 +2172,18 @@ void WindowTree::RemoveActivationParent(Id transport_window_id) { ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); - if (window) { - Display* display = GetDisplay(window); - if (display) - display->RemoveActivationParent(window); - else - DVLOG(1) << "RemoveActivationParent window not associated with display"; - } else { - DVLOG(1) << "RemoveActivationParent supplied invalid window id"; + if (!window) { + DVLOG(1) << "RemoveActivationParent failed (invalid window id)"; + return; } + + Display* display = GetDisplay(window); + if (!display) { + DVLOG(1) << "RemoveActivationParent window not associated with display"; + return; + } + + display->RemoveActivationParent(window); } void WindowTree::ActivateNextWindow() { @@ -2178,11 +2214,12 @@ ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); // Extended hit test region should only be set by the owner of the window. if (!window) { - DVLOG(1) << "SetExtendedHitArea supplied unknown window"; + DVLOG(1) << "SetExtendedHitArea failed (invalid window id)"; return; } if (window->id().client_id != id_) { - DVLOG(1) << "SetExtendedHitArea supplied window that client does not own"; + DVLOG(1) << "SetExtendedHitArea failed (supplied window that client does " + << "not own)"; return; } window->set_extended_hit_test_region(hit_area); @@ -2262,11 +2299,12 @@ ui::CursorData cursor) { DCHECK(window_manager_state_); ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); - if (window) { - window->SetNonClientCursor(std::move(cursor)); - } else { - DVLOG(1) << "trying to update non-client cursor of invalid window"; + if (!window) { + DVLOG(1) << "WmSetNonClientCursor failed (invalid window id)"; + return; } + + window->SetNonClientCursor(std::move(cursor)); } void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id, @@ -2274,7 +2312,7 @@ ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); if (window && window->id().client_id != id_) { - DVLOG(1) << "OnWmCreatedTopLevelWindow supplied invalid window id"; + DVLOG(1) << "OnWmCreatedTopLevelWindow failed (invalid window id)"; window_server_->WindowManagerSentBogusMessage(); window = nullptr; } @@ -2291,7 +2329,7 @@ DVLOG(3) << "OnAcceleratorAck client=" << id_; if (event_ack_id_ == 0 || event_id != event_ack_id_ || !accelerator_ack_callback_) { - DVLOG(1) << "OnAcceleratorAck supplied invalid event_id"; + DVLOG(1) << "OnAcceleratorAck failed (invalid event id)"; window_server_->WindowManagerSentBogusMessage(); return; }
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process index 70969f49..90e1b39 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process +++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -2,11 +2,18 @@ # See https://crbug.com/477150. # https://crbug.com/716085: Started failing after r466634 landed. +crbug.com/716085 http/tests/feature-policy/payment-allowed-by-container-policy-relocate.html [ Crash Failure ] crbug.com/716085 http/tests/feature-policy-experimental-features/vibrate-disabled.php [ Crash Failure ] +crbug.com/716085 http/tests/feature-policy-experimental-features/vibrate-enabledforall.php [ Crash Failure ] crbug.com/716085 http/tests/feature-policy-experimental-features/vibrate-enabledforself.php [ Crash Failure ] +crbug.com/716085 virtual/feature-policy/http/tests/feature-policy/fullscreen-allowed-by-container-policy.html [ Failure ] +crbug.com/716085 virtual/feature-policy/http/tests/feature-policy/fullscreen-allowed-by-container-policy-relocate.html [ Failure ] +crbug.com/716085 virtual/feature-policy/http/tests/feature-policy/payment-allowed-by-container-policy-relocate.html [ Crash ] +crbug.com/716085 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate.html [ Crash Failure ] crbug.com/716085 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-disabled.php [ Crash Failure ] crbug.com/716085 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php [ Crash Failure ] crbug.com/716085 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php [ Crash Failure ] +crbug.com/716085 virtual/mojo-loading/http/tests/feature-policy/payment-allowed-by-container-policy-relocate.html [ Failure ] crbug.com/716085 virtual/mojo-loading/http/tests/feature-policy-experimental-features/vibrate-disabled.php [ Crash Failure ] crbug.com/716085 virtual/mojo-loading/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php [ Crash Failure ] crbug.com/716085 virtual/mojo-loading/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php [ Crash Failure ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 2dcf955..bb2608f 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -84,6 +84,7 @@ # the tests for IndexedDB are skipped. crbug.com/506752 external/wpt/IndexedDB/ [ Skip ] crbug.com/506752 storage/indexeddb/ [ Skip ] +crbug.com/506752 virtual/sharedarraybuffer/storage/indexeddb/ [ Skip ] # ----------------------------------------------------------------- # Untriaged but known leaks of ActiveDOMObject (http).
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests index 5ff05d4..ddf3f1a2 100644 --- a/third_party/WebKit/LayoutTests/SlowTests +++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -9,7 +9,9 @@ # than 2 seconds in Release mode or 6 seconds in Debug mode should be listed here. crbug.com/24182 storage/indexeddb/objectstore-cursor.html [ Slow ] +crbug.com/24182 virtual/sharedarraybuffer/storage/indexeddb/objectstore-cursor.html [ Slow ] crbug.com/24182 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Slow ] +crbug.com/24182 virtual/sharedarraybuffer/storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Slow ] crbug.com/24182 editing/selection/modify_move/move-by-word-visually-mac.html [ Slow ] crbug.com/24182 editing/selection/modify_move/move-by-word-visually-multi-line.html [ Slow ] crbug.com/24182 compositing/culling/filter-occlusion-blur-large.html [ Slow ] @@ -266,7 +268,9 @@ crbug.com/364250 [ Debug ] virtual/threaded/animations/interpolation/transform-interpolation.html [ Slow ] crbug.com/364250 [ Debug ] virtual/threaded/animations/interpolation/webkit-transform-interpolation.html [ Slow ] crbug.com/402379 [ Win7 Debug ] storage/indexeddb/cursor-continue-validity.html [ Slow ] +crbug.com/402379 [ Win7 Debug ] virtual/sharedarraybuffer/storage/indexeddb/cursor-continue-validity.html [ Slow ] crbug.com/402379 [ Win7 Debug ] storage/indexeddb/mozilla/indexes.html [ Slow ] +crbug.com/402379 [ Win7 Debug ] virtual/sharedarraybuffer/storage/indexeddb/mozilla/indexes.html [ Slow ] crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Slow ] crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-sorting.html [ Slow ] crbug.com/440452 virtual/display_list_2d_canvas/fast/canvas/canvas-partial-invalidation-zoomed.html [ Slow ] @@ -385,9 +389,12 @@ # IDB Observer tests require multiple browsing contexts/workers interacting with # IndexedDB, which can be slow. crbug.com/660468 [ Linux ] storage/indexeddb/observer-frame.html [ Slow ] +crbug.com/660468 [ Linux ] virtual/sharedarraybuffer/storage/indexeddb/observer-frame.html [ Slow ] crbug.com/660468 [ Linux ] storage/indexeddb/observer-workers.html [ Slow ] +crbug.com/660468 [ Linux ] virtual/sharedarraybuffer/storage/indexeddb/observer-workers.html [ Slow ] crbug.com/660492 [ Linux ] storage/indexeddb/structured-clone.html [ Slow ] +crbug.com/660492 [ Linux ] virtual/sharedarraybuffer/storage/indexeddb/structured-clone.html [ Slow ] # Foreign fetch tests make many requests, and create multiple browsing contexts, # which can be very slow.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index dff3165c..84d27c30 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2334,19 +2334,13 @@ # This test fails with the stable release mode. crbug.com/694958 virtual/stable/http/tests/navigation/same-and-different-back.html [ Skip ] -# Failing because of module-related implementation/test issues and -# lack of inline module script support. +# Failing because of module-related implementation/test issues. crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Failure ] crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/errorhandling.html [ Failure ] crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/imports.html [ Failure Crash ] -crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Failure Timeout ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Pass Timeout ] crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html [ Failure Crash ] -# Inline module scripts are not yet supported. -crbug.com/715369 external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script.html [ Failure ] -crbug.com/715369 fast/dom/HTMLScriptElement/module-script.html [ Failure ] -crbug.com/715369 virtual/sharedarraybuffer/fast/dom/HTMLScriptElement/module-script.html [ Failure ] - # This test has a failure console message with specific performance # numbers so a consistent baseline cannot be added. This test could be # imported if the test passed or if the results for testharness tests @@ -3254,8 +3248,11 @@ crbug.com/678346 [ Win7 Debug ] fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] virtual/sharedarraybuffer/fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] storage/indexeddb/index-cursor.html [ Pass Timeout ] +crbug.com/678346 [ Win7 Debug ] virtual/sharedarraybuffer/storage/indexeddb/index-cursor.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ] +crbug.com/678346 [ Win7 Debug ] virtual/sharedarraybuffer/storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] storage/indexeddb/structured-clone.html [ Pass Timeout ] +crbug.com/678346 [ Win7 Debug ] virtual/sharedarraybuffer/storage/indexeddb/structured-clone.html [ Pass Timeout ] crbug.com/678487 http/tests/inspector/resource-tree/resource-tree-reload.html [ Failure Timeout Pass ] crbug.com/678487 virtual/mojo-loading/http/tests/inspector/resource-tree/resource-tree-reload.html [ Failure Timeout Pass ] @@ -3380,3 +3377,14 @@ crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flex-minimum-width-flex-items-001.xht [ Failure Pass ] crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flex-minimum-width-flex-items-003.xht [ Failure Pass ] crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flexbox_flex-natural-mixed-basis-auto.html [ Failure Pass ] + +crbug.com/716569 [ Android ] fast/block/float/centered-float-avoidance-complexity.html [ Failure ] +crbug.com/716569 [ Android ] fast/css3-text/css3-text-decoration/text-decoration-style-inherit.html [ Failure ] +crbug.com/716569 [ Android ] fast/events/reveal-link-when-focused.html [ Failure ] +crbug.com/716569 [ Android ] fast/overflow/position-fixed-transform-clipping.html [ Failure ] +crbug.com/716569 [ Android ] fast/table/border-collapsing/004.html [ Failure ] +crbug.com/716569 [ Android ] tables/mozilla/bugs/bug2479-3.html [ Failure ] +crbug.com/716569 [ Android ] tables/mozilla/bugs/bug2479-4.html [ Failure ] +crbug.com/716569 [ Android ] tables/mozilla/core/bloomberg.html [ Failure ] +crbug.com/716569 [ Android ] tables/mozilla_expected_failures/bugs/bug1055-2.html [ Failure ] +crbug.com/716569 [ Android ] tables/mozilla_expected_failures/bugs/bug2479-5.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index 00bf19d..52c8cc84 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -300,6 +300,12 @@ }, { "prefix": "sharedarraybuffer", + "base": "storage/indexeddb", + "args": ["--js-flags=--harmony-sharedarraybuffer", + "--enable-blink-features=SharedArrayBuffer"] + }, + { + "prefix": "sharedarraybuffer", "base": "webaudio", "args": ["--js-flags=--harmony-sharedarraybuffer", "--enable-blink-features=SharedArrayBuffer"]
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-select-crash.html b/third_party/WebKit/LayoutTests/fast/events/autoscroll-select-crash.html new file mode 100644 index 0000000..491da4e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/autoscroll-select-crash.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<iframe id=iframe srcdoc=" +<style> +.c:hover { display: block; } +.c { content: attr(class); width: 400px; height: 400px; } +</style> +<body id=body> + <select id=target autofocus=autofocus size=2 class=c></select> +</body>"></iframe> +<script> +var testObj; +function moveGesture() { + eventSender.mouseMoveTo(200, 51); + eventSender.mouseUp(); + testObj.done(); +} +function reloadIframe() { + iframe.contentWindow.location.reload(); + setTimeout(moveGesture, 50); +} +function go(test) { + testObj = test; + if (window.eventSender) { + eventSender.mouseMoveTo(200, 50); + eventSender.mouseDown(); + setTimeout(reloadIframe, 0); + } else { + test.done(); + } +} + +async_test(go); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-storage-dom-access.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-storage-dom-access.php index c63df42..68a56ae52 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-storage-dom-access.php +++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-storage-dom-access.php
@@ -34,13 +34,13 @@ function make_xorigin_test(storage_name, item_name) { var storage = window[storage_name]; return function(test) { - window.addEventListener('message', function(event) { + window.addEventListener('message', test.step_func(function(event) { if (event.data != 'ready' && event.data.type == storage_name) { assert_equals(event.data.value, null); assert_equals(storage.getItem(item_name), null); test.done(); } - }); + })); }; }
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-keys.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-keys.html index 012c9bf..fb3a5dd 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-keys.html +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-keys.html
@@ -15,38 +15,39 @@ var initData; // Create a list of multiple unique keyIds. - var keyIds = [ stringToUint8Array('keyid'), - stringToUint8Array('a really long keyid'), - new Uint8Array([0,1,2,3]), - new Uint8Array([0,1,2,3,4]), - new Uint8Array([0,1,2,3,4,5]), - new Uint8Array([0,1,2,3,4,6]), - stringToUint8Array('7'), - stringToUint8Array('8'), - stringToUint8Array('9'), - stringToUint8Array('10'), - stringToUint8Array('11'), - stringToUint8Array('12'), - stringToUint8Array('13'), - stringToUint8Array('14'), - stringToUint8Array('15'), - stringToUint8Array('16'), - stringToUint8Array('17'), - stringToUint8Array('18'), - stringToUint8Array('19'), - stringToUint8Array('20'), - stringToUint8Array('21'), - stringToUint8Array('22'), - stringToUint8Array('23'), - stringToUint8Array('24'), - stringToUint8Array('25') - ]; + const keyIds = [ + { keyId: stringToUint8Array('keyid'), status: 'usable' }, + { keyId: stringToUint8Array('a really long keyid'), status: 'usable' }, + { keyId: new Uint8Array([0,1,2,3]), status: 'usable' }, + { keyId: new Uint8Array([0,1,2,3,4]), status: 'usable' }, + { keyId: new Uint8Array([0,1,2,3,4,5]), status: 'usable' }, + { keyId: new Uint8Array([0,1,2,3,4,6]), status: 'usable' }, + { keyId: stringToUint8Array('7'), status: 'usable' }, + { keyId: stringToUint8Array('8'), status: 'usable' }, + { keyId: stringToUint8Array('9'), status: 'usable' }, + { keyId: stringToUint8Array('10'), status: 'usable' }, + { keyId: stringToUint8Array('11'), status: 'usable' }, + { keyId: stringToUint8Array('12'), status: 'usable' }, + { keyId: stringToUint8Array('13'), status: 'usable' }, + { keyId: stringToUint8Array('14'), status: 'usable' }, + { keyId: stringToUint8Array('15'), status: 'usable' }, + { keyId: stringToUint8Array('16'), status: 'usable' }, + { keyId: stringToUint8Array('17'), status: 'usable' }, + { keyId: stringToUint8Array('18'), status: 'usable' }, + { keyId: stringToUint8Array('19'), status: 'usable' }, + { keyId: stringToUint8Array('20'), status: 'usable' }, + { keyId: stringToUint8Array('21'), status: 'usable' }, + { keyId: stringToUint8Array('22'), status: 'usable' }, + { keyId: stringToUint8Array('23'), status: 'usable' }, + { keyId: stringToUint8Array('24'), status: 'usable' }, + { keyId: stringToUint8Array('25'), status: 'usable' } + ]; function processKeyStatusesChange(event) { // All 25 keyIds should be returned in keyStatuses. - verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: keyIds, unexpected: [] }); + verifyKeyStatuses(mediaKeySession.keyStatuses, keyIds); test.done(); } @@ -60,7 +61,7 @@ // Use the same key for all 25 keyIds. var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]); - var jwks = keyIds.map(function(keyId) { return createJWK(keyId, rawKey); }); + var jwks = keyIds.map(function(item) { return createJWK(item.keyId, rawKey); }); var jwkSet = stringToUint8Array(createJWKSet.apply(this, jwks)); mediaKeySession.update(jwkSet).catch(function(error) {
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-sessions.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-sessions.html index 4630709e..80be86f0 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-sessions.html +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-sessions.html
@@ -30,7 +30,7 @@ assert_equals(event.target, mediaKeySession1); // No keys added yet. - verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [], unexpected: [key1, key2] }); + verifyKeyStatuses(mediaKeySession1.keyStatuses, []); // Add key1 to session1. var jwkSet = stringToUint8Array(createJWKSet(createJWK(key1, rawKey1))); @@ -46,7 +46,8 @@ // Check that keyStatuses contains the expected key1 only. dumpKeyStatuses(mediaKeySession1.keyStatuses); - verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [key1], unexpected: [key2] }); + verifyKeyStatuses(mediaKeySession1.keyStatuses, + [ { keyId: key1, status: 'usable' } ]); // Now trigger a message event on session2. mediaKeySession2.generateRequest(initDataType, initData).catch(function(error) { @@ -60,10 +61,11 @@ assert_equals(event.target, mediaKeySession2); // session2 has no keys added yet. - verifyKeyStatuses(mediaKeySession2.keyStatuses, { expected: [], unexpected: [key1, key2] }); + verifyKeyStatuses(mediaKeySession2.keyStatuses, []); // session1 should still have 1 key. - verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [key1], unexpected: [key2] }); + verifyKeyStatuses(mediaKeySession1.keyStatuses, + [ { keyId: key1, status: 'usable' } ]); // Add key2 to session2. var jwkSet = stringToUint8Array(createJWKSet(createJWK(key2, rawKey2))); @@ -79,10 +81,12 @@ // Check that keyStatuses contains the expected key2 only. dumpKeyStatuses(mediaKeySession2.keyStatuses); - verifyKeyStatuses(mediaKeySession2.keyStatuses, { expected: [key2], unexpected: [key1] }); + verifyKeyStatuses(mediaKeySession2.keyStatuses, + [ { keyId: key2, status: 'usable' } ]); // session1 should still have 1 key. - verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [key1], unexpected: [key2] }); + verifyKeyStatuses(mediaKeySession1.keyStatuses, + [ { keyId: key1, status: 'usable' } ]); test.done(); } @@ -96,8 +100,8 @@ mediaKeySession2 = mediaKeys.createSession(); // There should be no keys defined on either session. - verifyKeyStatuses(mediaKeySession1.keyStatuses, { expected: [], unexpected: [key1, key2] }); - verifyKeyStatuses(mediaKeySession2.keyStatuses, { expected: [], unexpected: [key1, key2] }); + verifyKeyStatuses(mediaKeySession1.keyStatuses, []); + verifyKeyStatuses(mediaKeySession2.keyStatuses, []); // Bind all the event handlers now. waitForEventAndRunStep('message', mediaKeySession1, processMessage1, test);
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-updates.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-updates.html index 67d539e..dd81432 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-updates.html +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses-multiple-updates.html
@@ -27,7 +27,7 @@ function processMessage(event) { // No keys added yet. - verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [], unexpected: [key1, key2] }); + verifyKeyStatuses(mediaKeySession.keyStatuses, []); // Add key1 to the session. firstEvent = true; @@ -42,7 +42,8 @@ if (firstEvent) { // Verify that the session only contains key1. dumpKeyStatuses(mediaKeySession.keyStatuses); - verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [key1], unexpected: [key2] }); + verifyKeyStatuses(mediaKeySession.keyStatuses, + [ { keyId: key1, status: 'usable' } ]); // Now add key2 to the session. firstEvent = false; @@ -53,7 +54,8 @@ } else { // Verify that the session now contains key1 and key2. dumpKeyStatuses(mediaKeySession.keyStatuses); - verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [key1, key2] }); + verifyKeyStatuses(mediaKeySession.keyStatuses, + [ { keyId: key1, status: 'usable' }, { keyId: key2, status: 'usable' } ]); test.done(); }
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-remove-temporary.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-remove-temporary.html index 3ea6e78..a2cb3bf 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-remove-temporary.html +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-remove-temporary.html
@@ -34,12 +34,12 @@ }).then(function() { // After update() the session should have 1 usable key. verifyKeyStatuses(mediaKeySession.keyStatuses, - { expected: [keyId], unexpected: [] }, 'usable'); + [ { keyId: keyId, status: 'usable' } ]); return mediaKeySession.remove(); }).then(function() { // After remove() all keys should be 'released'. verifyKeyStatuses(mediaKeySession.keyStatuses, - { expected: [keyId], unexpected: [] }, 'released'); + [ { keyId: keyId, status: 'released' } ]); // After remove() the session expiry should be NaN. // ClearKey doesn't change set expiry times, but check // anyway. @@ -47,8 +47,7 @@ return mediaKeySession.close(); }).then(function() { // After close() there should be no keys. - verifyKeyStatuses(mediaKeySession.keyStatuses, - { expected: [], unexpected: [keyId] }); + verifyKeyStatuses(mediaKeySession.keyStatuses, []); }); }, 'Test MediaKeySession remove() function on temporary sessions');
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js index 38d1c99..a8d5829 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js
@@ -181,28 +181,18 @@ }); } -// Verify that |keyStatuses| contains just the keys in |keys.expected| -// and none of the keys in |keys.unexpected|. All expected keys should have -// status |status|. Example call: verifyKeyStatuses(mediaKeySession.keyStatuses, -// { expected: [key1], unexpected: [key2] }, 'usable'); -function verifyKeyStatuses(keyStatuses, keys, status) { - var expected = keys.expected || []; - var unexpected = keys.unexpected || []; - status = status || 'usable'; - +// Verify that |keyStatuses| contains just the keys in the array |expected|. +// Each entry specifies the keyId and status expected. +// Example call: verifyKeyStatuses(mediaKeySession.keyStatuses, +// [{keyId: key1, status: 'usable'}, {keyId: key2, status: 'released'}]); +function verifyKeyStatuses(keyStatuses, expected) { // |keyStatuses| should have same size as number of |keys.expected|. assert_equals(keyStatuses.size, expected.length); - // All |keys.expected| should be found. - expected.map(function(key) { - assert_true(keyStatuses.has(key)); - assert_equals(keyStatuses.get(key), status); - }); - - // All |keys.unexpected| should not be found. - unexpected.map(function(key) { - assert_false(keyStatuses.has(key)); - assert_equals(keyStatuses.get(key), undefined); + // All |expected| should be found. + expected.map(function(item) { + assert_true(keyStatuses.has(item.keyId)); + assert_equals(keyStatuses.get(item.keyId), item.status); }); }
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/shared-array-buffer-throws.html b/third_party/WebKit/LayoutTests/storage/indexeddb/shared-array-buffer-throws.html new file mode 100644 index 0000000..07a60c8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/storage/indexeddb/shared-array-buffer-throws.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>IndexedDB: Attempting to serialize a SharedArrayBuffer should throw</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/testharness-helpers.js"></script> +<script> + +if (window.SharedArrayBuffer) { + indexeddb_test( + (t, db) => { + db.createObjectStore('store'); + }, + (t, db) => { + const sab = new SharedArrayBuffer(256); + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + + assert_throws("DataCloneError", () => { + store.put({sab: sab}, 'key'); + }); + t.done(); + }, + 'Serializing SharedArrayBuffer throws DataClone error.'); +} else { + done(); +} + +</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/storage/indexeddb/README.txt b/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/storage/indexeddb/README.txt new file mode 100644 index 0000000..51001f0f --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/storage/indexeddb/README.txt
@@ -0,0 +1,3 @@ +# This suite runs the tests in with --js-flags=--harmony-sharedarraybuffer +# This enables the SharedArrayBuffer language feature in V8. +# See https://github.com/tc39/ecmascript_sharedmem for more information.
diff --git a/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiodestination.html b/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiodestination.html index adec749..4ccdbf73 100644 --- a/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiodestination.html +++ b/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiodestination.html
@@ -5,68 +5,56 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> - <script src="../resources/audio-testing.js"></script> - <script src="audionodeoptions.js"></script> + <script src="../resources/audit.js"></script> + <script src="new-audionodeoptions.js"></script> </head> <body> <script> - var context = new AudioContext(); + let context = new AudioContext(); - var audit = Audit.createTaskRunner(); + let audit = Audit.createTaskRunner(); - audit.defineTask("invalid constructor", function (taskDone) { - var node; - var success = true; - - success = Should("new MediaStreamAudioDestinationNode()", - function () { - node = new MediaStreamAudioDestinationNode(); - }) - .throw("TypeError"); - success = Should("new MediaStreamAudioDestinationNode(1)", - function () { - node = new MediaStreamAudioDestinationNode(1) - }) - .throw("TypeError") && success;; - success = Should("new MediaStreamAudioDestinationNode(context, 42)", - function () { - node = new MediaStreamAudioDestinationNode(context, 42) - }) - .throw("TypeError") && success;; - - taskDone(); + audit.define('initialize', (task, should) => { + context = initializeContext(should); + task.done(); }); - audit.defineTask("default constructor", function (taskDone) { - var node; - var success; - - success = Should("new MediaStreamAudioDestinationNode(context)", - function () { - node = new MediaStreamAudioDestinationNode(context); - }).notThrow() && success; - - success = Should("node instanceof MediaStreamAudioDestinationNode", - node instanceof MediaStreamAudioDestinationNode) - .beEqualTo(true) && success; - success = Should("node.channelCount", node.channelCount) - .beEqualTo(2) && success; - - taskDone(); + audit.define('invalid constructor', (task, should) => { + testInvalidConstructor( + should, 'MediaStreamAudioDestinationNode', context); + task.done(); }); - audit.defineTask("test AudioNodeOptions", function (taskDone) { - testAudioNodeOptions(context, "MediaStreamAudioDestinationNode", { - expectedChannelCount: { - // An arbitrary but valid, non-default count for this node. - value: 7 - } - }); - taskDone(); + audit.define('default constructor', (task, should) => { + let prefix = 'node0'; + let node = testDefaultConstructor( + should, 'MediaStreamAudioDestinationNode', context, { + prefix: prefix, + numberOfInputs: 1, + numberOfOutputs: 1, + channelCount: 2, + channelCountMode: 'max', + channelInterpretation: 'speakers' + }); + + testDefaultAttributes(should, node, prefix, []); + + task.done(); }); - audit.runTasks(); + audit.define('test AudioNodeOptions', (task, should) => { + testAudioNodeOptions( + should, context, 'MediaStreamAudioDestinationNode', { + channelCount: { + // An arbitrary but valid, non-default count for this node. + value: 7 + } + }); + task.done(); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiosource.html b/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiosource.html index 81247f7..97fa3aa 100644 --- a/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiosource.html +++ b/third_party/WebKit/LayoutTests/webaudio/constructor/mediastreamaudiosource.html
@@ -5,63 +5,45 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> - <script src="../resources/audio-testing.js"></script> + <script src="../resources/audit.js"></script> + <script src="new-audionodeoptions.js"></script> </head> <body> <script> - var context = new AudioContext(); + let context = new AudioContext(); - var audit = Audit.createTaskRunner(); + let audit = Audit.createTaskRunner(); - audit.defineTask("invalid constructor", function (taskDone) { - var node; - var success = true; - - success = Should("new MediaStreamAudioSourceNode()", function () { - node = new MediaStreamAudioSourceNode(); - }).throw("TypeError"); - success = Should("new MediaStreamAudioSourceNode(1)", function () { - node = new MediaStreamAudioSourceNode(1) && success; - }).throw("TypeError"); - success = Should("new MediaStreamAudioSourceNode(context, 42)", - function () { - node = new MediaStreamAudioSourceNode(context, 42) && success; - }).throw("TypeError"); - - Should("Invalid constructors", success) - .summarize( - "correctly threw errors", - "did not throw errors in all cases"); - - taskDone(); + audit.define('initialize', (task, should) => { + context = initializeContext(should); + task.done(); }); - audit.defineTask("constructor options", function (taskDone) { - var node; - var success = true; + audit.define('invalid constructor', (task, should) => { + testInvalidConstructor(should, 'MediaStreamAudioSourceNode', context); + task.done(); + }); - var options = { - mediaStream: new MediaStream() - }; + audit.define('constructor options', (task, should) => { + let node; + + let options = {mediaStream: new MediaStream()}; // We throw because the mediaStream has no tracks. But otherwise the // constructor worked. - success = Should("node = new MediaStreamAudioSourceNode(, " + JSON.stringify( - options) + ")", - function () { - node = new MediaStreamAudioSourceNode(context, options); - }).throw("InvalidStateError") && success; + should( + () => { + node = new MediaStreamAudioSourceNode(context, options); + }, + 'node = new MediaStreamAudioSourceNode(context, ' + + JSON.stringify(options) + ')') + .throw('InvalidStateError'); - Should("new MediaStreamAudioSourceNode(c, options)", success) - .summarize( - "constructed with correct attributes", - "was not constructed correctly"); - - taskDone(); + task.done(); }); - audit.runTasks(); + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html b/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html index 2968b1c..ea586581 100644 --- a/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html +++ b/third_party/WebKit/LayoutTests/webaudio/constructor/waveshaper.html
@@ -5,8 +5,8 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> - <script src="../resources/audio-testing.js"></script> - <script src="audionodeoptions.js"></script> + <script src="../resources/audit.js"></script> + <script src="new-audionodeoptions.js"></script> </head> <body> @@ -15,99 +15,57 @@ var audit = Audit.createTaskRunner(); - audit.defineTask("initialize", function (taskDone) { - Should("Construct Offline context", function () { - context = new OfflineAudioContext(1, 1, 48000); - }).notThrow(); - taskDone(); + audit.define('initialize', (task, should) => { + context = initializeContext(should); + task.done(); }); - audit.defineTask("incorrect construction", function (taskDone) { - var success = true; - - success = Should("new WaveShaperNode()", function () { - new WaveShaperNode(); - }).throw("TypeError"); - success = Should("new WaveShaperNode(1)", function () { - new WaveShaperNode(1); - }).throw("TypeError") && success; - success = Should("new WaveShaperNode(context, 42)", function () { - new WaveShaperNode(context, 42); - }).throw("TypeError") && success; - - success = Should("Invalid constructors", success) - .summarize( - "correctly threw errors", - "did not throw errors in all cases"); - taskDone(); + audit.define('incorrect construction', (task, should) => { + testInvalidConstructor(should, 'WaveShaperNode', context); + task.done(); }); - audit.defineTask("valid default construction", function (taskDone) { - var node; - - success = Should("node0 = new WaveShaperNode(context)", function () { - node = new WaveShaperNode(context); - }).notThrow(); - success = Should("node0.curve", node.curve).beEqualTo(null) && success; - success = Should("node0.oversample", node.oversample).beEqualTo("none") && success; - - success = Should("node0.channelCount", node.channelCount) - .beEqualTo(2) && success; - success = Should("node0.channelCountMode", node.channelCountMode) - .beEqualTo("max") && success; - success = Should("node0.channelInterpretation", node.channelInterpretation) - .beEqualTo("speakers") && success; - - Should("new WaveShaperNode(context)", success) - .summarize( - "constructed node with correct attributes", - "did not construct correct node correctly") - - taskDone(); - }); - - audit.defineTask("test AudioNodeOptions", function (taskDone) { - testAudioNodeOptions(context, "WaveShaperNode"); - taskDone(); - }); - - audit.defineTask("valid non-default", function (taskDone) { - // Construct an WaveShaperNode with options - var options = { - curve: Float32Array.from([1,2,3]), - oversample: "4x" - }; - var node; - - var message = "node1 = new WaveShaperNode(, " + JSON.stringify(options) + ")"; - success = Should(message, function () { - node = new WaveShaperNode(context, options); - }).notThrow(); - success = Should("node1.curve", node.curve) - .beEqualToArray(options.curve) && success; - success = Should("node1.oversample", node.oversample) - .beEqualTo(options.oversample) && success; - - Should("new WaveShaper() with options", success) - .summarize( - "constructed with correct attributes", - "was not constructed correctly"); - - taskDone(); - }); - - if (window.SharedArrayBuffer) { - audit.defineTask("invalid setCurve", function (taskDone) { - var node = new WaveShaperNode(context); - - Should("WaveShaper.curve = SharedArrayBuffer view", function () { - node.curve = new Float32Array(new SharedArrayBuffer(16)); - }).throw("TypeError"); - taskDone(); + audit.define('valid default construction', (task, should) => { + let prefix = 'node0'; + let node = testDefaultConstructor(should, 'WaveShaperNode', context, { + prefix: prefix, + numberOfInputs: 1, + numberOfOutputs: 1, + channelCount: 2, + channelCountMode: 'max', + channelInterpretation: 'speakers' }); - } - audit.runTasks(); + testDefaultAttributes(should, node, prefix, [ + {name: 'curve', value: null}, {name: 'oversample', value: 'none'} + ]); + + task.done(); + }); + + audit.define('test AudioNodeOptions', (task, should) => { + testAudioNodeOptions(should, context, 'WaveShaperNode'); + task.done(); + }); + + audit.define('valid non-default', (task, should) => { + // Construct an WaveShaperNode with options + var options = {curve: Float32Array.from([1, 2, 3]), oversample: '4x'}; + var node; + + var message = + 'node1 = new WaveShaperNode(, ' + JSON.stringify(options) + ')'; + should(() => { + node = new WaveShaperNode(context, options); + }, message).notThrow(); + should(node.curve, 'node1.curve').beEqualToArray(options.curve); + should(node.oversample, 'node1.oversample') + .beEqualTo(options.oversample); + + task.done(); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h index 6990ec8..c3d560a 100644 --- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h +++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h
@@ -95,6 +95,9 @@ Transferables* transferables = nullptr; WebBlobInfoArray* blob_info = nullptr; bool write_wasm_to_stream = false; + // Set when serializing a value for storage; e.g. when writing to + // IndexedDB. + bool for_storage = false; }; static PassRefPtr<SerializedScriptValue> Serialize(v8::Isolate*, v8::Local<v8::Value>,
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp index bc0cf537..dee9be5 100644 --- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
@@ -51,7 +51,8 @@ serializer_(script_state_->GetIsolate(), this), transferables_(options.transferables), blob_info_array_(options.blob_info), - inline_wasm_(options.write_wasm_to_stream) {} + inline_wasm_(options.write_wasm_to_stream), + for_storage_(options.for_storage) {} RefPtr<SerializedScriptValue> V8ScriptValueSerializer::Serialize( v8::Local<v8::Value> value, @@ -117,32 +118,37 @@ void V8ScriptValueSerializer::FinalizeTransfer( ExceptionState& exception_state) { - if (!transferables_ && shared_array_buffers_.IsEmpty()) - return; - // TODO(jbroman): Strictly speaking, this is not correct; transfer should // occur in the order of the transfer list. // https://html.spec.whatwg.org/multipage/infrastructure.html#structuredclonewithtransfer + v8::Isolate* isolate = script_state_->GetIsolate(); + + // The order of ArrayBuffers and SharedArrayBuffers matters; we use the index + // into this array for deserialization. ArrayBufferArray array_buffers; - array_buffers.AppendVector(transferables_->array_buffers); + if (transferables_) + array_buffers.AppendVector(transferables_->array_buffers); array_buffers.AppendVector(shared_array_buffers_); - v8::Isolate* isolate = script_state_->GetIsolate(); - serialized_script_value_->TransferArrayBuffers(isolate, array_buffers, - exception_state); - if (exception_state.HadException()) - return; + if (!array_buffers.IsEmpty()) { + serialized_script_value_->TransferArrayBuffers(isolate, array_buffers, + exception_state); + if (exception_state.HadException()) + return; + } - serialized_script_value_->TransferImageBitmaps( - isolate, transferables_->image_bitmaps, exception_state); - if (exception_state.HadException()) - return; + if (transferables_) { + serialized_script_value_->TransferImageBitmaps( + isolate, transferables_->image_bitmaps, exception_state); + if (exception_state.HadException()) + return; - serialized_script_value_->TransferOffscreenCanvas( - isolate, transferables_->offscreen_canvases, exception_state); - if (exception_state.HadException()) - return; + serialized_script_value_->TransferOffscreenCanvas( + isolate, transferables_->offscreen_canvases, exception_state); + if (exception_state.HadException()) + return; + } } void V8ScriptValueSerializer::WriteUTF8String(const String& string) { @@ -399,6 +405,18 @@ v8::Maybe<uint32_t> V8ScriptValueSerializer::GetSharedArrayBufferId( v8::Isolate* isolate, v8::Local<v8::SharedArrayBuffer> v8_shared_array_buffer) { + if (for_storage_) { + DCHECK(exception_state_); + DCHECK_EQ(isolate, script_state_->GetIsolate()); + ExceptionState exception_state(isolate, exception_state_->Context(), + exception_state_->InterfaceName(), + exception_state_->PropertyName()); + exception_state.ThrowDOMException( + kDataCloneError, + "A SharedArrayBuffer can not be serialized for storage."); + return v8::Nothing<uint32_t>(); + } + DOMSharedArrayBuffer* shared_array_buffer = V8SharedArrayBuffer::toImpl(v8_shared_array_buffer);
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h index d01afa95..8606080 100644 --- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h +++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h
@@ -99,6 +99,7 @@ WebBlobInfoArray* blob_info_array_ = nullptr; ArrayBufferArray shared_array_buffers_; bool inline_wasm_ = false; + bool for_storage_ = false; #if DCHECK_IS_ON() bool serialize_invoked_ = false; #endif
diff --git a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp index 2595a3be..1bb3b3a 100644 --- a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp +++ b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp
@@ -18,7 +18,7 @@ ElementVisibilityObserver::~ElementVisibilityObserver() = default; -void ElementVisibilityObserver::Start() { +void ElementVisibilityObserver::Start(float threshold) { DCHECK(!intersection_observer_); ExecutionContext* context = element_->GetExecutionContext(); @@ -26,8 +26,7 @@ Document& document = ToDocument(*context); intersection_observer_ = IntersectionObserver::Create( - Vector<Length>(), Vector<float>({std::numeric_limits<float>::min()}), - &document, + {} /* root_margin */, {threshold}, &document, WTF::Bind(&ElementVisibilityObserver::OnVisibilityChanged, WrapWeakPersistent(this))); DCHECK(intersection_observer_); @@ -53,7 +52,8 @@ void ElementVisibilityObserver::OnVisibilityChanged( const HeapVector<Member<IntersectionObserverEntry>>& entries) { - bool is_visible = entries.back()->intersectionRatio() > 0.f; + bool is_visible = entries.back()->intersectionRatio() > + intersection_observer_->thresholds()[0]; (*callback_.get())(is_visible); }
diff --git a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h index 9e0b69c..ef982b86 100644 --- a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h +++ b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h
@@ -33,7 +33,8 @@ ElementVisibilityObserver(Element*, std::unique_ptr<VisibilityCallback>); virtual ~ElementVisibilityObserver(); - void Start(); + // The |threshold| is the minimum fraction that needs to be visible. + void Start(float threshold = 0.0); void Stop(); void DeliverObservationsForTesting();
diff --git a/third_party/WebKit/Source/core/dom/Modulator.h b/third_party/WebKit/Source/core/dom/Modulator.h index 98bdad2..da1d8a0 100644 --- a/third_party/WebKit/Source/core/dom/Modulator.h +++ b/third_party/WebKit/Source/core/dom/Modulator.h
@@ -87,6 +87,9 @@ ModuleGraphLevel, SingleModuleClient*) = 0; + virtual void FetchDescendantsForInlineScript(ModuleScript*, + ModuleTreeClient*) = 0; + // Synchronously retrieves a single module script from existing module map // entry. // Note: returns nullptr if the module map entry is still "fetching".
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp index 1be380b8..e5e4f35d 100644 --- a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp +++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
@@ -84,6 +84,12 @@ tree_linker_registry_->Fetch(request, ancestor_list, level, this, client); } +void ModulatorImpl::FetchDescendantsForInlineScript(ModuleScript* module_script, + ModuleTreeClient* client) { + tree_linker_registry_->FetchDescendantsForInlineScript(module_script, this, + client); +} + void ModulatorImpl::FetchSingle(const ModuleScriptFetchRequest& request, ModuleGraphLevel level, SingleModuleClient* client) {
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.h b/third_party/WebKit/Source/core/dom/ModulatorImpl.h index 2819a57..1087f69 100644 --- a/third_party/WebKit/Source/core/dom/ModulatorImpl.h +++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.h
@@ -46,6 +46,8 @@ SecurityOrigin* GetSecurityOrigin() override; void FetchTree(const ModuleScriptFetchRequest&, ModuleTreeClient*) override; + void FetchDescendantsForInlineScript(ModuleScript*, + ModuleTreeClient*) override; void FetchTreeInternal(const ModuleScriptFetchRequest&, const AncestorList&, ModuleGraphLevel,
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp index bd911121..20cdc1e 100644 --- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp +++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -33,11 +33,12 @@ if (result.IsNull()) return nullptr; - return CreateInternal(modulator, result, base_url, nonce, parser_state, - credentials_mode); + return CreateInternal(source_text, modulator, result, base_url, nonce, + parser_state, credentials_mode); } ModuleScript* ModuleScript::CreateInternal( + const String& source_text, Modulator* modulator, ScriptModule result, const KURL& base_url, @@ -52,8 +53,10 @@ // Step 10. Set script's parser state to the parser state. // Step 11. Set script's credentials mode to the credentials mode provided. // Step 12. Return script. - ModuleScript* module_script = new ModuleScript( - modulator, result, base_url, nonce, parser_state, credentials_mode); + // [not specced] |source_text| is saved for CSP checks. + ModuleScript* module_script = + new ModuleScript(modulator, result, base_url, nonce, parser_state, + credentials_mode, source_text); // Step 5, a part of ParseModule(): Passing script as the last parameter // here ensures result.[[HostDefined]] will be script. @@ -69,8 +72,9 @@ const String& nonce, ParserDisposition parser_state, WebURLRequest::FetchCredentialsMode credentials_mode) { - return CreateInternal(modulator, record, base_url, nonce, parser_state, - credentials_mode); + String dummy_source_text = ""; + return CreateInternal(dummy_source_text, modulator, record, base_url, nonce, + parser_state, credentials_mode); } void ModuleScript::SetInstantiationErrorAndClearRecord(ScriptValue error) { @@ -125,10 +129,7 @@ } String ModuleScript::InlineSourceTextForCSP() const { - // Currently we don't support inline module scripts. - // TODO(hiroshige): Implement this. - NOTREACHED(); - return String(); + return source_text_; } } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h index 4b9c5dd7..22002a4 100644 --- a/third_party/WebKit/Source/core/dom/ModuleScript.h +++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -79,16 +79,19 @@ const KURL& base_url, const String& nonce, ParserDisposition parser_state, - WebURLRequest::FetchCredentialsMode credentials_mode) + WebURLRequest::FetchCredentialsMode credentials_mode, + const String& source_text) : settings_object_(settings_object), record_(record), base_url_(base_url), instantiation_error_(this), nonce_(nonce), parser_state_(parser_state), - credentials_mode_(credentials_mode) {} + credentials_mode_(credentials_mode), + source_text_(source_text) {} - static ModuleScript* CreateInternal(Modulator*, + static ModuleScript* CreateInternal(const String& source_text, + Modulator*, ScriptModule, const KURL& base_url, const String& nonce, @@ -142,6 +145,9 @@ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-credentials-mode const WebURLRequest::FetchCredentialsMode credentials_mode_; + + // For CSP check. + const String source_text_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index 31c1d93..3ca2f29e 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -321,7 +321,21 @@ CrossOriginAttributeValue cross_origin = GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue()); - // 16. is handled below. + // 16. "Let module script credentials mode be determined by switching + // on CORS setting:" + WebURLRequest::FetchCredentialsMode credentials_mode = + WebURLRequest::kFetchCredentialsModeOmit; + switch (cross_origin) { + case kCrossOriginAttributeNotSet: + credentials_mode = WebURLRequest::kFetchCredentialsModeOmit; + break; + case kCrossOriginAttributeAnonymous: + credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin; + break; + case kCrossOriginAttributeUseCredentials: + credentials_mode = WebURLRequest::kFetchCredentialsModeInclude; + break; + } // 17. "If the script element has a nonce attribute, // then let cryptographic nonce be that attribute's value. @@ -390,9 +404,6 @@ else encoding = element_document.characterSet(); - // Step 16 is skipped because "module script credentials" is not used - // for classic scripts. - // 18. "If the script element has an integrity attribute, // then let integrity metadata be that attribute's value. // Otherwise, let integrity metadata be the empty string." @@ -420,22 +431,6 @@ // Steps 14 and 18 are skipped because they are not used in module // scripts. - // 16. "Let module script credentials mode be determined by switching - // on CORS setting:" - WebURLRequest::FetchCredentialsMode credentials_mode = - WebURLRequest::kFetchCredentialsModeOmit; - switch (cross_origin) { - case kCrossOriginAttributeNotSet: - credentials_mode = WebURLRequest::kFetchCredentialsModeOmit; - break; - case kCrossOriginAttributeAnonymous: - credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin; - break; - case kCrossOriginAttributeUseCredentials: - credentials_mode = WebURLRequest::kFetchCredentialsModeInclude; - break; - } - DCHECK(RuntimeEnabledFeatures::moduleScriptsEnabled()); Modulator* modulator = Modulator::From( ToScriptStateForMainWorld(element_document.GetFrame())); @@ -482,16 +477,34 @@ break; // - "module": - case ScriptType::kModule: - // TODO(hiroshige): Implement inline module scripts. - element_document.AddConsoleMessage(ConsoleMessage::Create( - kJSMessageSource, kErrorMessageLevel, - "Inline module script is not yet supported", - SourceLocation::Create(element_document.Url().GetString(), - script_start_position.line_.OneBasedInt(), - script_start_position.column_.OneBasedInt(), - nullptr))); - return false; + case ScriptType::kModule: { + // 1. "Let base URL be the script element's node document's document + // base URL." + KURL base_url = element_document.BaseURL(); + + // 2. "Let script be the result of creating a module script using + // source text, settings, base URL, cryptographic nonce, + // parser state, and module script credentials mode." + Modulator* modulator = Modulator::From( + ToScriptStateForMainWorld(element_document.GetFrame())); + ModuleScript* module_script = ModuleScript::Create( + ScriptContent(), modulator, base_url, nonce, parser_state, + credentials_mode, kSharableCrossOrigin); + + // 3. "If this returns null, set the script's script to null and abort + // these substeps; the script is ready." + if (!module_script) + return false; + + // 4. "Fetch the descendants of script (using an empty ancestor list). + // When this asynchronously completes, set the script's script to + // the result. At that time, the script is ready." + DCHECK(!module_tree_client_); + module_tree_client_ = ModulePendingScriptTreeClient::Create(); + modulator->FetchDescendantsForInlineScript(module_script, + module_tree_client_); + break; + } } }
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn index e984133a4..0a92134 100644 --- a/third_party/WebKit/Source/core/editing/BUILD.gn +++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -285,6 +285,7 @@ "commands/DeleteSelectionCommandTest.cpp", "commands/InsertIncrementalTextCommandTest.cpp", "commands/InsertListCommandTest.cpp", + "commands/InsertTextCommandTest.cpp", "commands/ReplaceSelectionCommandTest.cpp", "commands/SetCharacterDataCommandTest.cpp", "commands/SplitTextNodeCommandTest.cpp",
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp index a328886..d707fdeb 100644 --- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -199,6 +199,8 @@ } void ApplyStyleCommand::DoApply(EditingState* editing_state) { + DCHECK(StartPosition().IsNotNull()); + DCHECK(EndPosition().IsNotNull()); switch (property_level_) { case kPropertyDefault: { // Apply the block-centric properties of the style.
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp index aeeb848..e803959 100644 --- a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
@@ -276,7 +276,7 @@ GetDocument().GetFrame()->GetEditor().TypingStyle()) { typing_style->PrepareToApplyAt(end_position, EditingStyle::kPreserveWritingDirection); - if (!typing_style->IsEmpty()) { + if (!typing_style->IsEmpty() && !EndingSelection().IsNone()) { ApplyStyle(typing_style, editing_state); if (editing_state->IsAborted()) return;
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/InsertTextCommandTest.cpp new file mode 100644 index 0000000..98290a1b --- /dev/null +++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommandTest.cpp
@@ -0,0 +1,34 @@ +// Copyright (c) 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 "core/editing/commands/InsertTextCommand.h" + +#include "core/editing/EditingTestBase.h" +#include "core/editing/FrameSelection.h" + +namespace blink { + +class InsertTextCommandTest : public EditingTestBase {}; + +// http://crbug.com/714311 +TEST_F(InsertTextCommandTest, WithTypingStyle) { + SetBodyContent("<div contenteditable=true><option id=sample></option></div>"); + Element* const sample = GetDocument().getElementById("sample"); + Selection().SetSelection( + SelectionInDOMTree::Builder().Collapse(Position(sample, 0)).Build()); + // Register typing style to make |InsertTextCommand| to attempt to apply + // style to inserted text. + GetDocument().execCommand("fontSizeDelta", false, "+3", ASSERT_NO_EXCEPTION); + CompositeEditCommand* const command = + InsertTextCommand::Create(GetDocument(), "x"); + command->Apply(); + + EXPECT_EQ( + "<div contenteditable=\"true\"><option id=\"sample\">x</option></div>", + GetDocument().body()->innerHTML()) + << "Content of OPTION is distributed into shadow node as text" + "without applying typing style."; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp index 864057a4..f8c491e 100644 --- a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp +++ b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp
@@ -114,13 +114,7 @@ } } -// Failing on Android: crbug.com/667913 -#if OS(ANDROID) -#define MAYBE_RecordingFeatures DISABLED_RecordingFeatures -#else -#define MAYBE_RecordingFeatures RecordingFeatures -#endif -TEST(UseCounterTest, MAYBE_RecordingFeatures) { +TEST(UseCounterTest, RecordingFeatures) { UseCounter use_counter; HistogramBasicTest<UseCounter::Feature>( kFeaturesHistogramName, kLegacyFeaturesHistogramName, @@ -175,13 +169,7 @@ "https://dummysite.com/", 1 /* page visit bucket */); } -// Failing on Android: crbug.com/667913 -#if OS(ANDROID) -#define MAYBE_SVGImageContextFeatures DISABLED_SVGImageContextFeatures -#else -#define MAYBE_SVGImageContextFeatures SVGImageContextFeatures -#endif -TEST(UseCounterTest, MAYBE_SVGImageContextFeatures) { +TEST(UseCounterTest, SVGImageContextFeatures) { UseCounter use_counter(UseCounter::kSVGImageContext); HistogramBasicTest<UseCounter::Feature>( kSVGFeaturesHistogramName, kLegacyFeaturesHistogramName, @@ -238,13 +226,7 @@ 1 /* page visit bucket */); } -// Failing on Android: crbug.com/667913 -#if OS(ANDROID) -#define MAYBE_InspectorDisablesMeasurement DISABLED_InspectorDisablesMeasurement -#else -#define MAYBE_InspectorDisablesMeasurement InspectorDisablesMeasurement -#endif -TEST(UseCounterTest, MAYBE_InspectorDisablesMeasurement) { +TEST(UseCounterTest, InspectorDisablesMeasurement) { UseCounter use_counter; HistogramTester histogram_tester; @@ -311,13 +293,7 @@ visits_count + property_count); } -// Failing on Android: crbug.com/667913 -#if OS(ANDROID) -#define MAYBE_MutedDocuments DISABLED_MutedDocuments -#else -#define MAYBE_MutedDocuments MutedDocuments -#endif -TEST(UseCounterTest, MAYBE_MutedDocuments) { +TEST(UseCounterTest, MutedDocuments) { UseCounter use_counter; HistogramTester histogram_tester;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h index c79fcd1..82e4d3e 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -724,6 +724,7 @@ friend class HTMLMediaElementEventListenersTest; friend class HTMLVideoElement; friend class MediaControlsOrientationLockDelegateTest; + friend class MediaControlsRotateToFullscreenDelegateTest; Member<AutoplayPolicy> autoplay_policy_;
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp index 98fe955d..9830da4 100644 --- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -1518,9 +1518,13 @@ !mouse_event->ButtonDown()) return; - if (Page* page = GetDocument().GetPage()) + if (LayoutObject* object = GetLayoutObject()) + object->GetFrameView()->UpdateAllLifecyclePhasesExceptPaint(); + + if (Page* page = GetDocument().GetPage()) { page->GetAutoscrollController().StartAutoscrollForSelection( GetLayoutObject()); + } // Mousedown didn't happen in this element. if (last_on_change_selection_.IsEmpty()) return;
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp index bb88304..9667803 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp +++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -738,7 +738,7 @@ event, mouse_down_pos_, drag_start_pos_, mouse_press_node_.Get(), last_known_mouse_position_); - // The call into handleMouseDraggedEvent may have caused a re-layout, + // The call into HandleMouseDraggedEvent may have caused a re-layout, // so get the LayoutObject again. layout_object = target_node->GetLayoutObject(); @@ -747,8 +747,15 @@ !frame_->Selection().SelectedHTMLForClipboard().IsEmpty()) { if (AutoscrollController* controller = scroll_manager_->GetAutoscrollController()) { - controller->StartAutoscrollForSelection(layout_object); - mouse_down_may_start_autoscroll_ = false; + // Avoid updating the lifecycle unless it's possible to autoscroll. + layout_object->GetFrameView()->UpdateAllLifecyclePhasesExceptPaint(); + + // The lifecycle update above may have invalidated the previous layout. + layout_object = target_node->GetLayoutObject(); + if (layout_object) { + controller->StartAutoscrollForSelection(layout_object); + mouse_down_may_start_autoscroll_ = false; + } } }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 5ebf1b6..548907dd 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -1756,7 +1756,7 @@ } void LayoutBox::ImageChanged(WrappedImagePtr image, const IntRect*) { - // TODO(chrishtr): support PaintInvalidationDelayedFull for animated border + // TODO(chrishtr): support kPaintInvalidationDelayedFull for animated border // images. if ((StyleRef().BorderImage().GetImage() && StyleRef().BorderImage().GetImage()->Data() == image) || @@ -1878,14 +1878,11 @@ return; // Do regular full paint invalidation if the object with - // PaintInvalidationDelayedFull is onscreen. - if (IntersectsVisibleViewport()) { - // Conservatively assume the delayed paint invalidation was caused by - // background image change. - SetBackgroundChangedSinceLastPaintInvalidation(); - SetShouldDoFullPaintInvalidationWithoutGeometryChange( - kPaintInvalidationFull); - } + // kPaintInvalidationDelayedFull is onscreen. + // Conservatively assume the delayed paint invalidation was caused by + // background image change. + SetBackgroundChangedSinceLastPaintInvalidation(); + SetShouldDoFullPaintInvalidationWithoutGeometryChange(kPaintInvalidationFull); } PaintInvalidationReason LayoutBox::InvalidatePaint(
diff --git a/third_party/WebKit/Source/core/layout/LayoutImage.cpp b/third_party/WebKit/Source/core/layout/LayoutImage.cpp index 73d3a8a..0ae3d20 100644 --- a/third_party/WebKit/Source/core/layout/LayoutImage.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutImage.cpp
@@ -170,10 +170,10 @@ return; } - if (ImageResource() && ImageResource()->MaybeAnimated()) - SetShouldDoFullPaintInvalidation(kPaintInvalidationDelayedFull); - else - SetShouldDoFullPaintInvalidation(kPaintInvalidationFull); + SetShouldDoFullPaintInvalidationWithoutGeometryChange( + ImageResource() && ImageResource()->MaybeAnimated() + ? kPaintInvalidationDelayedFull + : kPaintInvalidationFull); // Tell any potential compositing layers that the image needs updating. ContentChanged(kImageChanged);
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp index 9e1440b..e032e104 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.cpp
@@ -9,6 +9,7 @@ #include "core/dom/ModuleScript.h" #include "core/loader/modulescript/ModuleScriptFetchRequest.h" #include "core/loader/modulescript/ModuleTreeLinkerRegistry.h" +#include "platform/WebTaskRunner.h" #include "platform/loader/fetch/ResourceLoadingLog.h" #include "platform/wtf/Vector.h" @@ -30,6 +31,36 @@ return fetcher; } +ModuleTreeLinker* ModuleTreeLinker::FetchDescendantsForInlineScript( + ModuleScript* module_script, + Modulator* modulator, + ModuleTreeLinkerRegistry* registry, + ModuleTreeClient* client) { + AncestorList empty_ancestor_list; + + // Substep 4 in "module" case in Step 22 of "prepare a script":" + // https://html.spec.whatwg.org/#prepare-a-script + + // 4. "Fetch the descendants of script (using an empty ancestor list)." + ModuleTreeLinker* fetcher = + new ModuleTreeLinker(empty_ancestor_list, modulator, registry, client); + fetcher->module_script_ = module_script; + fetcher->AdvanceState(State::kFetchingSelf); + + // "When this asynchronously completes, set the script's script to + // the result. At that time, the script is ready." + // + // Currently we execute "internal module script graph + // fetching procedure" Step 5- in addition to "fetch the descendants", + // which is not specced yet. https://github.com/whatwg/html/issues/2544 + // TODO(hiroshige): Fix the implementation and/or comments once the spec + // is updated. + modulator->TaskRunner()->PostTask( + BLINK_FROM_HERE, + WTF::Bind(&ModuleTreeLinker::FetchDescendants, WrapPersistent(fetcher))); + return fetcher; +} + ModuleTreeLinker::ModuleTreeLinker(const AncestorList& ancestor_list_with_url, Modulator* modulator, ModuleTreeLinkerRegistry* registry,
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h index 03daabf..ead8d19 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinker.h
@@ -31,6 +31,12 @@ Modulator*, ModuleTreeLinkerRegistry*, ModuleTreeClient*); + static ModuleTreeLinker* FetchDescendantsForInlineScript( + ModuleScript*, + Modulator*, + ModuleTreeLinkerRegistry*, + ModuleTreeClient*); + virtual ~ModuleTreeLinker() = default; DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp index e07dd3e..0a2b6f34 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.cpp
@@ -27,6 +27,17 @@ return fetcher; } +ModuleTreeLinker* ModuleTreeLinkerRegistry::FetchDescendantsForInlineScript( + ModuleScript* module_script, + Modulator* modulator, + ModuleTreeClient* client) { + ModuleTreeLinker* fetcher = ModuleTreeLinker::FetchDescendantsForInlineScript( + module_script, modulator, this, client); + DCHECK(fetcher->IsFetching()); + active_tree_linkers_.insert(fetcher); + return fetcher; +} + void ModuleTreeLinkerRegistry::ReleaseFinishedFetcher( ModuleTreeLinker* fetcher) { DCHECK(fetcher->HasFinished());
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h index a038896..0f845fd7 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerRegistry.h
@@ -16,6 +16,7 @@ class ModuleTreeClient; class ModuleTreeLinker; enum class ModuleGraphLevel; +class ModuleScript; // ModuleTreeLinkerRegistry keeps active ModuleTreeLinkers alive. class CORE_EXPORT ModuleTreeLinkerRegistry @@ -31,6 +32,9 @@ ModuleGraphLevel, Modulator*, ModuleTreeClient*); + ModuleTreeLinker* FetchDescendantsForInlineScript(ModuleScript*, + Modulator*, + ModuleTreeClient*); private: ModuleTreeLinkerRegistry() = default;
diff --git a/third_party/WebKit/Source/core/page/AutoscrollController.cpp b/third_party/WebKit/Source/core/page/AutoscrollController.cpp index 4765eaf..ab94c72 100644 --- a/third_party/WebKit/Source/core/page/AutoscrollController.cpp +++ b/third_party/WebKit/Source/core/page/AutoscrollController.cpp
@@ -76,8 +76,6 @@ // it's already active. if (autoscroll_type_ != kNoAutoscroll) return; - if (layout_object) - layout_object->GetFrameView()->UpdateAllLifecyclePhasesExceptPaint(); LayoutBox* scrollable = LayoutBox::FindAutoscrollable(layout_object); if (!scrollable) scrollable =
diff --git a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp index 404322f..4e422e72 100644 --- a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
@@ -850,7 +850,7 @@ break; } default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp index b0d1505d..0bb07bb 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -701,7 +701,7 @@ case kBorderFillBox: break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; }
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp index e6e2a3a..4b6758b 100644 --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -1088,7 +1088,7 @@ PaintCompositionUnderline(paint_info.context, box_origin, underline); } break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } } }
diff --git a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp index bc8dfa72..6140df6 100644 --- a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp
@@ -35,7 +35,7 @@ context.FillRect(marker); break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; } }
diff --git a/third_party/WebKit/Source/core/paint/MediaControlsPainter.cpp b/third_party/WebKit/Source/core/paint/MediaControlsPainter.cpp index 64d2317..f1a2d5c 100644 --- a/third_party/WebKit/Source/core/paint/MediaControlsPainter.cpp +++ b/third_party/WebKit/Source/core/paint/MediaControlsPainter.cpp
@@ -68,7 +68,7 @@ g_media_control_image_map->Set(name, image); return image; } - ASSERT_NOT_REACHED(); + NOTREACHED(); return 0; } @@ -548,7 +548,7 @@ case kMediaOverlayCastOffButton: return PaintMediaButton(paint_info.context, rect, media_overlay_cast_off); default: - ASSERT_NOT_REACHED(); + NOTREACHED(); return false; } }
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp index 10ae5f8..437e8d21 100644 --- a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp +++ b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
@@ -147,7 +147,7 @@ right_.width, bottom_.width)); break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; } } @@ -224,7 +224,7 @@ horizontal_tile_rule_); break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; } }
diff --git a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp index 8f2770f6..0398a136 100644 --- a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
@@ -101,7 +101,7 @@ return 0; } default: - ASSERT_NOT_REACHED(); + NOTREACHED(); return 0; } }
diff --git a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h index 57411c3..ca24c8233 100644 --- a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h +++ b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
@@ -117,10 +117,10 @@ TestDisplayItem(const DisplayItemClient& client, Type type) : DisplayItem(client, type, sizeof(*this)) {} - void Replay(GraphicsContext&) const final { ASSERT_NOT_REACHED(); } + void Replay(GraphicsContext&) const final { NOTREACHED(); } void AppendToWebDisplayItemList(const IntRect&, WebDisplayItemList*) const final { - ASSERT_NOT_REACHED(); + NOTREACHED(); } };
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp index dc4f14d..d1e2ead7c9 100644 --- a/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintInvalidationTest.cpp
@@ -6,6 +6,8 @@ #include "core/layout/LayoutTestHelper.h" #include "core/layout/LayoutView.h" #include "core/paint/PaintLayer.h" +#include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/paint/RasterInvalidationTracking.h" #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -20,6 +22,15 @@ PaintInvalidationTest() : ScopedRootLayerScrollingForTest(GetParam()), RenderingTest(SingleChildLocalFrameClient::Create()) {} + + protected: + const RasterInvalidationTracking* GetRasterInvalidationTracking() const { + // TODO(wangxianzhu): Test SPv2. + return GetLayoutView() + .Layer() + ->GraphicsLayerBacking() + ->GetRasterInvalidationTracking(); + } }; INSTANTIATE_TEST_CASE_P(All, PaintInvalidationTest, ::testing::Bool()); @@ -153,6 +164,43 @@ GetDocument().View()->UpdateAllLifecyclePhases(); } +TEST_P(PaintInvalidationTest, DelayedFullPaintInvalidation) { + EnableCompositing(); + SetBodyInnerHTML( + "<style>body { margin: 0 }</style>" + "<div style='height: 4000px'></div>" + "<div id='target' style='width: 100px; height: 100px; background: blue'>" + "</div>"); + + auto* target = GetLayoutObjectByElementId("target"); + target->SetShouldDoFullPaintInvalidationWithoutGeometryChange( + kPaintInvalidationDelayedFull); + EXPECT_EQ(kPaintInvalidationDelayedFull, + target->FullPaintInvalidationReason()); + EXPECT_FALSE(target->NeedsPaintOffsetAndVisualRectUpdate()); + + GetDocument().View()->SetTracksPaintInvalidations(true); + GetDocument().View()->UpdateAllLifecyclePhases(); + EXPECT_EQ(nullptr, GetRasterInvalidationTracking()); + EXPECT_EQ(kPaintInvalidationDelayedFull, + target->FullPaintInvalidationReason()); + EXPECT_FALSE(target->NeedsPaintOffsetAndVisualRectUpdate()); + GetDocument().View()->SetTracksPaintInvalidations(false); + + GetDocument().View()->SetTracksPaintInvalidations(true); + // Scroll target into view. + GetDocument().domWindow()->scrollTo(0, 4000); + GetDocument().View()->UpdateAllLifecyclePhases(); + const auto& raster_invalidations = + GetRasterInvalidationTracking()->tracked_raster_invalidations; + ASSERT_EQ(1u, raster_invalidations.size()); + EXPECT_EQ(kPaintInvalidationNone, target->FullPaintInvalidationReason()); + EXPECT_EQ(IntRect(0, 4000, 100, 100), raster_invalidations[0].rect); + EXPECT_EQ(kPaintInvalidationFull, raster_invalidations[0].reason); + EXPECT_FALSE(target->NeedsPaintOffsetAndVisualRectUpdate()); + GetDocument().View()->SetTracksPaintInvalidations(false); +}; + } // namespace } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp index 17402de1..df2ac59 100644 --- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -510,8 +510,9 @@ void PaintInvalidator::ProcessPendingDelayedPaintInvalidations() { for (auto target : pending_delayed_paint_invalidations_) { - target->GetMutableForPainting().SetShouldDoFullPaintInvalidation( - kPaintInvalidationDelayedFull); + target->GetMutableForPainting() + .SetShouldDoFullPaintInvalidationWithoutGeometryChange( + kPaintInvalidationDelayedFull); } }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp index d00f1a5..de41d0c 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -1806,7 +1806,7 @@ if (Node* e = r->GetNode()) return e; } - ASSERT_NOT_REACHED(); + NOTREACHED(); return 0; }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp index 7817508e..cbfc784b 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -135,9 +135,14 @@ ->ShouldThrottleRendering()) return kFullyPainted; - // If this layer is totally invisible then there is nothing to paint. - if (PaintedOutputInvisible(painting_info)) + // If this layer is totally invisible then there is nothing to paint. In SPv2 + // we simplify this optimization by painting even when effectively invisible + // but skipping the painted content during layerization in + // PaintArtifactCompositor. + if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() && + PaintedOutputInvisible(painting_info)) { return kFullyPainted; + } if (paint_layer_.PaintsWithTransparency(painting_info.GetGlobalPaintFlags())) paint_flags |= kPaintLayerHaveTransparency;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp index 8fe045b8..78b94d8 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -32,23 +32,19 @@ : ScopedRootLayerScrollingForTest(GetParam().root_layer_scrolling), PaintControllerPaintTestBase(GetParam().slimming_paint_v2) {} - void ExpectPaintedOutputVisibility(const char* element_name, - bool expected_spv1) { - ExpectPaintedOutputVisibility(element_name, expected_spv1, expected_spv1); - } + void ExpectPaintedOutputInvisible(const char* element_name, + bool expected_value) { + // The optimization to skip painting for effectively-invisible content is + // limited to SPv1. + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) + return; - void ExpectPaintedOutputVisibility(const char* element_name, - bool expected_spv1, - bool expected_spv2) { PaintLayer* target_layer = ToLayoutBox(GetLayoutObjectByElementId(element_name))->Layer(); PaintLayerPaintingInfo painting_info(nullptr, LayoutRect(), kGlobalPaintNormalPhase, LayoutSize()); bool invisible = PaintLayerPainter(*target_layer).PaintedOutputInvisible(painting_info); - bool expected_value = RuntimeEnabledFeatures::slimmingPaintV2Enabled() - ? expected_spv2 - : expected_spv1; EXPECT_EQ(expected_value, invisible) << "Failed painted output visibility [spv2_enabled=" << RuntimeEnabledFeatures::slimmingPaintV2Enabled() @@ -795,21 +791,21 @@ TEST_P(PaintLayerPainterTest, DontPaintWithTinyOpacity) { SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.0001'></div>"); - ExpectPaintedOutputVisibility("target", true, false); + ExpectPaintedOutputInvisible("target", true); } TEST_P(PaintLayerPainterTest, DoPaintWithTinyOpacityAndWillChangeOpacity) { SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.0001; " "will-change: opacity'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithTinyOpacityAndBackdropFilter) { SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.0001;" " backdrop-filter: blur(2px);'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, @@ -817,20 +813,20 @@ SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.0001;" " backdrop-filter: blur(2px); will-change: opacity'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithCompositedTinyOpacity) { SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.0001;" " will-change: transform'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithNonTinyOpacity) { SetBodyInnerHTML( "<div id='target' style='background: blue; opacity: 0.1'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithEffectAnimationZeroOpacity) { @@ -848,10 +844,10 @@ "} " "</style> " "<div id='target'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } -TEST_P(PaintLayerPainterTest, DontPaintWithTransformAnimationZeroOpacity) { +TEST_P(PaintLayerPainterTest, DoPaintWithTransformAnimationZeroOpacity) { SetBodyInnerHTML( "<style> " "div#target { " @@ -865,7 +861,7 @@ "} " "</style> " "<div id='target'>x</div></div>"); - ExpectPaintedOutputVisibility("target", false, true); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, @@ -884,7 +880,7 @@ "} " "</style> " "<div id='target'>x</div></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithWillChangeOpacity) { @@ -897,7 +893,7 @@ "}" "</style> " "<div id='target'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, DoPaintWithZeroOpacityAndWillChangeOpacity) { @@ -911,7 +907,7 @@ "}" "</style> " "<div id='target'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } TEST_P(PaintLayerPainterTest, @@ -926,7 +922,7 @@ "}" "</style> " "<div id='target'></div>"); - ExpectPaintedOutputVisibility("target", false); + ExpectPaintedOutputInvisible("target", false); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index 1e2d5f0..c3dcf5fc 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1163,7 +1163,7 @@ (Box().Size().Height() - Box().BorderBottom() - scrollbar.Height()) .ToInt()); - ASSERT_NOT_REACHED(); + NOTREACHED(); return IntSize(); } @@ -1876,6 +1876,10 @@ non_composited_main_thread_scrolling_reasons_ |= MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText; } + if (!layer->GetLayoutObject().Style()->IsStackingContext()) { + non_composited_main_thread_scrolling_reasons_ |= + MainThreadScrollingReason::kIsNotStackingContextAndLCDText; + } needs_composited_scrolling = false; }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index a7a8c6a..5fabc8b 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -1105,7 +1105,7 @@ context.current = context.fixed_position; break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } if (object.IsBox()) {
diff --git a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp index 48277ef..6d6bf86 100644 --- a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
@@ -16,10 +16,7 @@ namespace blink { -GraphicsContext* SVGFilterRecordingContext::BeginContent( - FilterData* filter_data) { - DCHECK_EQ(filter_data->state_, FilterData::kInitial); - +GraphicsContext* SVGFilterRecordingContext::BeginContent() { // Create a new context so the contents of the filter can be drawn and cached. paint_controller_ = PaintController::Create(); context_ = WTF::WrapUnique(new GraphicsContext(*paint_controller_)); @@ -30,69 +27,53 @@ paint_controller_->UpdateCurrentPaintChunkProperties( nullptr, PropertyTreeState::Root()); } - - filter_data->state_ = FilterData::kRecordingContent; return context_.get(); } -void SVGFilterRecordingContext::EndContent(FilterData* filter_data) { - DCHECK_EQ(filter_data->state_, FilterData::kRecordingContent); - - Filter* filter = filter_data->last_effect->GetFilter(); - SourceGraphic* source_graphic = filter->GetSourceGraphic(); - DCHECK(source_graphic); - +sk_sp<PaintRecord> SVGFilterRecordingContext::EndContent( + const FloatRect& bounds) { // Use the context that contains the filtered content. DCHECK(paint_controller_); DCHECK(context_); - context_->BeginRecording(filter->FilterRegion()); + context_->BeginRecording(bounds); paint_controller_->CommitNewDisplayItems(); - paint_controller_->GetPaintArtifact().Replay(filter->FilterRegion(), - *context_); + paint_controller_->GetPaintArtifact().Replay(bounds, *context_); - SkiaImageFilterBuilder::BuildSourceGraphic(source_graphic, - context_->EndRecording()); - + sk_sp<PaintRecord> content = context_->EndRecording(); // Content is cached by the source graphic so temporaries can be freed. paint_controller_ = nullptr; context_ = nullptr; + return content; +} - filter_data->state_ = FilterData::kReadyToPaint; +void SVGFilterRecordingContext::Abort() { + if (!paint_controller_) + return; + EndContent(FloatRect()); } static void PaintFilteredContent(GraphicsContext& context, const LayoutObject& object, - FilterData* filter_data) { + const FloatRect& bounds, + FilterEffect* effect) { if (LayoutObjectDrawingRecorder::UseCachedDrawingIfPossible( context, object, DisplayItem::kSVGFilter)) return; - FloatRect filter_bounds = - filter_data ? filter_data->last_effect->GetFilter()->FilterRegion() - : FloatRect(); LayoutObjectDrawingRecorder recorder(context, object, DisplayItem::kSVGFilter, - filter_bounds); - if (!filter_data || filter_data->state_ != FilterData::kReadyToPaint) - return; - DCHECK(filter_data->last_effect->GetFilter()->GetSourceGraphic()); - - filter_data->state_ = FilterData::kPaintingFilter; - - FilterEffect* last_effect = filter_data->last_effect; + bounds); sk_sp<SkImageFilter> image_filter = - SkiaImageFilterBuilder::Build(last_effect, kColorSpaceDeviceRGB); + SkiaImageFilterBuilder::Build(effect, kColorSpaceDeviceRGB); context.Save(); // Clip drawing of filtered image to the minimum required paint rect. - context.ClipRect(last_effect->MapRect(object.StrokeBoundingBox())); + context.ClipRect(effect->MapRect(object.StrokeBoundingBox())); - context.BeginLayer(1, SkBlendMode::kSrcOver, &filter_bounds, kColorFilterNone, + context.BeginLayer(1, SkBlendMode::kSrcOver, &bounds, kColorFilterNone, std::move(image_filter)); context.EndLayer(); context.Restore(); - - filter_data->state_ = FilterData::kReadyToPaint; } GraphicsContext* SVGFilterPainter::PrepareEffect( @@ -127,34 +108,57 @@ FilterData* filter_data = FilterData::Create(); filter_data->last_effect = filter->LastEffect(); filter_data->node_map = node_map; + DCHECK_EQ(filter_data->state_, FilterData::kInitial); // TODO(pdr): Can this be moved out of painter? filter_.SetFilterDataForLayoutObject(const_cast<LayoutObject*>(&object), filter_data); - return recording_context.BeginContent(filter_data); + filter_data->state_ = FilterData::kRecordingContent; + return recording_context.BeginContent(); } void SVGFilterPainter::FinishEffect( const LayoutObject& object, SVGFilterRecordingContext& recording_context) { FilterData* filter_data = filter_.GetFilterDataForLayoutObject(&object); - if (filter_data) { - // A painting cycle can occur when an FeImage references a source that - // makes use of the FeImage itself. This is the first place we would hit - // the cycle so we reset the state and continue. - if (filter_data->state_ == FilterData::kPaintingFilterCycleDetected) - filter_data->state_ = FilterData::kPaintingFilter; - - // Check for RecordingContent here because we may can be re-painting - // without re-recording the contents to be filtered. - if (filter_data->state_ == FilterData::kRecordingContent) - recording_context.EndContent(filter_data); - - if (filter_data->state_ == FilterData::kRecordingContentCycleDetected) - filter_data->state_ = FilterData::kRecordingContent; + if (!filter_data) { + // Our state was torn down while we were being painted (selection style for + // <text> can have this effect), or it was never created (invalid filter.) + // In the former case we may have been in the process of recording content, + // so make sure we put recording state into a consistent state. + recording_context.Abort(); + return; } - PaintFilteredContent(recording_context.PaintingContext(), object, - filter_data); + + // A painting cycle can occur when an FeImage references a source that + // makes use of the FeImage itself. This is the first place we would hit + // the cycle so we reset the state and continue. + if (filter_data->state_ == FilterData::kPaintingFilterCycleDetected) { + filter_data->state_ = FilterData::kPaintingFilter; + return; + } + if (filter_data->state_ == FilterData::kRecordingContentCycleDetected) { + filter_data->state_ = FilterData::kRecordingContent; + return; + } + + // Check for RecordingContent here because we may can be re-painting + // without re-recording the contents to be filtered. + Filter* filter = filter_data->last_effect->GetFilter(); + FloatRect bounds = filter->FilterRegion(); + if (filter_data->state_ == FilterData::kRecordingContent) { + DCHECK(filter->GetSourceGraphic()); + sk_sp<PaintRecord> content = recording_context.EndContent(bounds); + SkiaImageFilterBuilder::BuildSourceGraphic(filter->GetSourceGraphic(), + std::move(content)); + filter_data->state_ = FilterData::kReadyToPaint; + } + + DCHECK_EQ(filter_data->state_, FilterData::kReadyToPaint); + filter_data->state_ = FilterData::kPaintingFilter; + PaintFilteredContent(recording_context.PaintingContext(), object, bounds, + filter_data->last_effect); + filter_data->state_ = FilterData::kReadyToPaint; } } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/SVGFilterPainter.h b/third_party/WebKit/Source/core/paint/SVGFilterPainter.h index 3770f2f..7ff20e2 100644 --- a/third_party/WebKit/Source/core/paint/SVGFilterPainter.h +++ b/third_party/WebKit/Source/core/paint/SVGFilterPainter.h
@@ -12,7 +12,6 @@ namespace blink { -class FilterData; class LayoutObject; class LayoutSVGResourceFilter; @@ -24,8 +23,9 @@ explicit SVGFilterRecordingContext(GraphicsContext& initial_context) : initial_context_(initial_context) {} - GraphicsContext* BeginContent(FilterData*); - void EndContent(FilterData*); + GraphicsContext* BeginContent(); + sk_sp<PaintRecord> EndContent(const FloatRect&); + void Abort(); GraphicsContext& PaintingContext() const { return initial_context_; }
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp index 67c0256..c0eb9ea 100644 --- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -202,7 +202,7 @@ // Markers don't apply to text break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; } } @@ -296,7 +296,7 @@ if (decoration == kTextDecorationLineThrough) return font_metrics.FloatAscent() * 3 / 8.0f; - ASSERT_NOT_REACHED(); + NOTREACHED(); return 0.0f; } @@ -393,7 +393,7 @@ case PT_MARKERS: break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } } }
diff --git a/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp b/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp index 84d7338c..0fb3093 100644 --- a/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp
@@ -126,7 +126,7 @@ PaintMarkers(paint_context.GetPaintInfo(), bounding_box); break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); break; } }
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.cpp b/third_party/WebKit/Source/core/testing/DummyModulator.cpp index f58e35e..e5dcd699 100644 --- a/third_party/WebKit/Source/core/testing/DummyModulator.cpp +++ b/third_party/WebKit/Source/core/testing/DummyModulator.cpp
@@ -75,6 +75,11 @@ NOTREACHED(); } +void DummyModulator::FetchDescendantsForInlineScript(ModuleScript*, + ModuleTreeClient*) { + NOTREACHED(); +} + ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&) { NOTREACHED(); return nullptr;
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.h b/third_party/WebKit/Source/core/testing/DummyModulator.h index c665005..a3725c7 100644 --- a/third_party/WebKit/Source/core/testing/DummyModulator.h +++ b/third_party/WebKit/Source/core/testing/DummyModulator.h
@@ -44,6 +44,8 @@ void FetchSingle(const ModuleScriptFetchRequest&, ModuleGraphLevel, SingleModuleClient*) override; + void FetchDescendantsForInlineScript(ModuleScript*, + ModuleTreeClient*) override; ModuleScript* GetFetchedModuleScript(const KURL&) override; void FetchNewSingleModule(const ModuleScriptFetchRequest&, ModuleGraphLevel,
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js index b237136..e34c95c 100644 --- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js +++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js
@@ -370,11 +370,9 @@ } /** - * @param {?SDK.Target} target * @param {!Array.<!SDK.PaintProfilerLogItem>} log */ - setCommandLog(target, log) { - this._target = target; + setCommandLog(log) { this._log = log; /** @type {!Map<!SDK.PaintProfilerLogItem>} */ this._treeItemCache = new Map();
diff --git a/third_party/WebKit/Source/devtools/front_end/layers/LayerPaintProfilerView.js b/third_party/WebKit/Source/devtools/front_end/layers/LayerPaintProfilerView.js index e6bb324..629ff48 100644 --- a/third_party/WebKit/Source/devtools/front_end/layers/LayerPaintProfilerView.js +++ b/third_party/WebKit/Source/devtools/front_end/layers/LayerPaintProfilerView.js
@@ -34,7 +34,7 @@ * @this {Layers.LayerPaintProfilerView} */ function setSnapshotAndLog(snapshot, log) { - this._logTreeView.setCommandLog(snapshot && snapshot.target(), log || []); + this._logTreeView.setCommandLog(log || []); this._paintProfilerView.setSnapshotAndLog(snapshot, log || [], null); if (snapshot) snapshot.release();
diff --git a/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js b/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js index b620d46..c39653b 100644 --- a/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js +++ b/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js
@@ -34,7 +34,9 @@ Layers.LayerTreeModel = class extends SDK.SDKModel { constructor(target) { super(target); + this._layerTreeAgent = target.layerTreeAgent(); target.registerLayerTreeDispatcher(new Layers.LayerTreeDispatcher(this)); + this._paintProfilerModel = /** @type {!SDK.PaintProfilerModel} */ (target.model(SDK.PaintProfilerModel)); var resourceTreeModel = target.model(SDK.ResourceTreeModel); if (resourceTreeModel) { resourceTreeModel.addEventListener( @@ -48,7 +50,7 @@ if (!this._enabled) return; this._enabled = false; - this.target().layerTreeAgent().disable(); + this._layerTreeAgent.disable(); } enable() { @@ -61,8 +63,8 @@ _forceEnable() { this._lastPaintRectByLayerId = {}; if (!this._layerTree) - this._layerTree = new Layers.AgentLayerTree(this.target()); - this.target().layerTreeAgent().enable(); + this._layerTree = new Layers.AgentLayerTree(this); + this._layerTreeAgent.enable(); } /** @@ -134,10 +136,11 @@ */ Layers.AgentLayerTree = class extends SDK.LayerTreeBase { /** - * @param {?SDK.Target} target + * @param {!Layers.LayerTreeModel} layerTreeModel */ - constructor(target) { - super(target); + constructor(layerTreeModel) { + super(layerTreeModel.target()); + this._layerTreeModel = layerTreeModel; } /** @@ -186,7 +189,7 @@ if (layer) layer._reset(layers[i]); else - layer = new Layers.AgentLayer(this.target(), layers[i]); + layer = new Layers.AgentLayer(this._layerTreeModel, layers[i]); this._layersById[layerId] = layer; var backendNodeId = layers[i].backendNodeId; if (backendNodeId) @@ -218,11 +221,11 @@ */ Layers.AgentLayer = class { /** - * @param {?SDK.Target} target + * @param {!Layers.LayerTreeModel} layerTreeModel * @param {!Protocol.LayerTree.Layer} layerPayload */ - constructor(target, layerPayload) { - this._target = target; + constructor(layerTreeModel, layerPayload) { + this._layerTreeModel = layerTreeModel; this._reset(layerPayload); } @@ -401,14 +404,9 @@ * @param {function(!Array.<string>)} callback */ requestCompositingReasons(callback) { - if (!this._target) { - callback([]); - return; - } - var wrappedCallback = Protocol.inspectorBackend.wrapClientCallback( callback, 'Protocol.LayerTree.reasonsForCompositingLayer(): ', undefined, []); - this._target.layerTreeAgent().compositingReasons(this.id(), wrappedCallback); + this._layerTreeModel._layerTreeAgent.compositingReasons(this.id(), wrappedCallback); } /** @@ -436,11 +434,11 @@ * @return {!Array<!Promise<?SDK.SnapshotWithRect>>} */ snapshots() { - var rect = {x: 0, y: 0, width: this.width(), height: this.height()}; - var promise = this._target.layerTreeAgent().makeSnapshot( - this.id(), (error, snapshotId) => error || !this._target ? - null : - {rect: rect, snapshot: new SDK.PaintProfilerSnapshot(this._target, snapshotId)}); + var promise = this._layerTreeModel._paintProfilerModel.makeSnapshot(this.id()).then(snapshot => { + if (!snapshot) + return null; + return {rect: {x: 0, y: 0, width: this.width(), height: this.height()}, snapshot: snapshot}; + }); return [promise]; }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js index 6f07ce2..058e3e18 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
@@ -27,49 +27,66 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +SDK.PaintProfilerModel = class extends SDK.SDKModel { + /** + * @param {!SDK.Target} target + */ + constructor(target) { + super(target); + this._layerTreeAgent = target.layerTreeAgent(); + } + + /** + * @param {!Array.<!SDK.PictureFragment>} fragments + * @return {!Promise<?SDK.PaintProfilerSnapshot>} + */ + loadSnapshotFromFragments(fragments) { + return this._layerTreeAgent.loadSnapshot( + fragments, (error, snapshotId) => error ? null : new SDK.PaintProfilerSnapshot(this, snapshotId)); + } + + /** + * @param {string} encodedPicture + * @return {!Promise<?SDK.PaintProfilerSnapshot>} + */ + loadSnapshot(encodedPicture) { + var fragment = {x: 0, y: 0, picture: encodedPicture}; + return this.loadSnapshotFromFragments([fragment]); + } + + /** + * @param {string} layerId + * @return {!Promise<?SDK.PaintProfilerSnapshot>} + */ + makeSnapshot(layerId) { + return this._layerTreeAgent.makeSnapshot( + layerId, (error, snapshotId) => error ? null : new SDK.PaintProfilerSnapshot(this, snapshotId)); + } +}; + +SDK.SDKModel.register(SDK.PaintProfilerModel, SDK.Target.Capability.DOM, false); + /** * @typedef {!{x: number, y: number, picture: string}} */ SDK.PictureFragment; -/** - * @unrestricted - */ SDK.PaintProfilerSnapshot = class { /** - * @param {!SDK.Target} target + * @param {!SDK.PaintProfilerModel} paintProfilerModel * @param {string} snapshotId */ - constructor(target, snapshotId) { - this._target = target; + constructor(paintProfilerModel, snapshotId) { + this._paintProfilerModel = paintProfilerModel; this._id = snapshotId; this._refCount = 1; } - /** - * @param {!SDK.Target} target - * @param {!Array.<!SDK.PictureFragment>} fragments - * @return {!Promise<?SDK.PaintProfilerSnapshot>} - */ - static loadFromFragments(target, fragments) { - return target.layerTreeAgent().loadSnapshot( - fragments, (error, snapshotId) => error ? null : new SDK.PaintProfilerSnapshot(target, snapshotId)); - } - - /** - * @param {!SDK.Target} target - * @param {string} encodedPicture - * @return {!Promise<?SDK.PaintProfilerSnapshot>} - */ - static load(target, encodedPicture) { - var fragment = {x: 0, y: 0, picture: encodedPicture}; - return SDK.PaintProfilerSnapshot.loadFromFragments(target, [fragment]); - } - release() { console.assert(this._refCount > 0, 'release is already called on the object'); if (!--this._refCount) - this._target.layerTreeAgent().releaseSnapshot(this._id); + this._paintProfilerModel._layerTreeAgent.releaseSnapshot(this._id); } addReference() { @@ -78,20 +95,13 @@ } /** - * @return {!SDK.Target} - */ - target() { - return this._target; - } - - /** * @param {?number} firstStep * @param {?number} lastStep * @param {?number} scale * @return {!Promise<?string>} */ replay(firstStep, lastStep, scale) { - return this._target.layerTreeAgent().replaySnapshot( + return this._paintProfilerModel._layerTreeAgent.replaySnapshot( this._id, firstStep || undefined, lastStep || undefined, scale || 1.0, (error, str) => error ? null : str); } @@ -102,14 +112,14 @@ profile(clipRect, callback) { var wrappedCallback = Protocol.inspectorBackend.wrapClientCallback(callback, 'Protocol.LayerTree.profileSnapshot(): '); - this._target.layerTreeAgent().profileSnapshot(this._id, 5, 1, clipRect || undefined, wrappedCallback); + this._paintProfilerModel._layerTreeAgent.profileSnapshot(this._id, 5, 1, clipRect || undefined, wrappedCallback); } /** * @return {!Promise<?Array<!SDK.PaintProfilerLogItem>>} */ commandLog() { - return this._target.layerTreeAgent().snapshotCommandLog(this._id, processLog); + return this._paintProfilerModel._layerTreeAgent.snapshotCommandLog(this._id, processLog); /** * @param {?string} error @@ -125,7 +135,6 @@ } }; - /** * @typedef {!{method: string, params: ?Object<string, *>}} */
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js index 446c177..edd10a8 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js
@@ -122,7 +122,12 @@ break; case Timeline.TimelineSelection.Type.Frame: var frame = /** @type {!TimelineModel.TimelineFrame} */ (this._selection.object()); - var filmStripFrame = Timeline.TimelineUIUtils.filmStripModelFrame(this._model.filmStripModel(), frame); + var screenshotTime = frame.idle ? + frame.startTime : + frame.endTime; // For idle frames, look at the state at the beginning of the frame. + var filmStripFrame = this._model.filmStripModel().frameByTimestamp(screenshotTime); + if (filmStripFrame && filmStripFrame.timestamp - frame.endTime > 10) + filmStripFrame = null; this._setContent(Timeline.TimelineUIUtils.generateDetailsContentForFrame(frame, filmStripFrame)); if (frame.layerTree) { var layersView = this._layersView(); @@ -204,11 +209,11 @@ * @param {!SDK.TracingModel.Event} event */ _showEventInPaintProfiler(event) { - const target = SDK.targetManager.mainTarget(); - if (!target) + const paintProfilerModel = SDK.targetManager.models(SDK.PaintProfilerModel)[0]; + if (!paintProfilerModel) return; const paintProfilerView = this._paintProfilerView(); - const hasProfileData = paintProfilerView.setEvent(target, event); + const hasProfileData = paintProfilerView.setEvent(paintProfilerModel, event); if (!hasProfileData) return; if (this._tabbedPane.hasTab(Timeline.TimelineDetailsView.Tab.PaintProfiler))
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js index 71c8a93..45b6cab 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
@@ -364,7 +364,7 @@ this._imageByFrame(frames[0]).then(image => { if (this._drawGeneration !== drawGeneration) return; - if (!image || !image.naturalWidth || !image.naturalHeight) + if (!image.naturalWidth || !image.naturalHeight) return; var imageHeight = this.height() - 2 * Timeline.TimelineFilmStripOverview.Padding; var imageWidth = Math.ceil(imageHeight * image.naturalWidth / image.naturalHeight); @@ -376,15 +376,34 @@ /** * @param {!SDK.FilmStripModel.Frame} frame - * @return {!Promise<?HTMLImageElement>} + * @return {!Promise<!HTMLImageElement>} */ _imageByFrame(frame) { var imagePromise = this._frameToImagePromise.get(frame); if (!imagePromise) { - imagePromise = frame.imageDataPromise().then(data => UI.loadImage(data ? 'data:image/jpg;base64,' + data : '')); + imagePromise = frame.imageDataPromise().then(createImage); this._frameToImagePromise.set(frame, imagePromise); } return imagePromise; + + /** + * @param {?string} data + * @return {!Promise<!HTMLImageElement>} + */ + function createImage(data) { + var fulfill; + var promise = new Promise(f => fulfill = f); + + var image = /** @type {!HTMLImageElement} */ (createElement('img')); + if (data) { + image.src = 'data:image/jpg;base64,' + data; + image.addEventListener('load', () => fulfill(image)); + image.addEventListener('error', () => fulfill(image)); + } else { + fulfill(image); + } + return promise; + } } /** @@ -419,12 +438,12 @@ /** * @param {number} x - * @param {?HTMLImageElement} image + * @param {!HTMLImageElement} image * @this {Timeline.TimelineFilmStripOverview} */ function drawFrameImage(x, image) { // Ignore draws deferred from a previous update call. - if (this._drawGeneration !== drawGeneration || !image) + if (this._drawGeneration !== drawGeneration) return; context.drawImage(image, x, 1, imageWidth, imageHeight); } @@ -448,13 +467,12 @@ /** * @this {Timeline.TimelineFilmStripOverview} - * @param {?HTMLImageElement} image + * @param {!HTMLImageElement} image * @return {?Element} */ function createFrameElement(image) { var element = createElementWithClass('div', 'frame'); - if (image) - element.createChild('div', 'thumbnail').appendChild(image); + element.createChild('div', 'thumbnail').appendChild(image); this._lastFrame = frame; this._lastElement = element; return element;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js index 96a0b5c9..c29d53583 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
@@ -47,7 +47,6 @@ this._performanceModel = null; /** @type {?TimelineModel.TimelineModel} */ this._model = null; - this._expandedFrameBarHeight = 5; // Number of bars. this._consoleColorGenerator = new PerfUI.FlameChart.ColorGenerator({min: 30, max: 55}, {min: 70, max: 100, count: 6}, 50, 0.7); @@ -71,10 +70,8 @@ (Object.assign({}, defaultGroupStyle, {padding: 2, nestingLevel: 1, collapsible: false})); this._staticHeader = /** @type {!PerfUI.FlameChart.GroupStyle} */ (Object.assign({}, defaultGroupStyle, {collapsible: false})); - this._framesHeader = /** @type {!PerfUI.FlameChart.GroupStyle} */ - (Object.assign({}, defaultGroupStyle, {useFirstLineForOverview: true, shareHeaderLine: true})); this._interactionsHeaderLevel1 = /** @type {!PerfUI.FlameChart.GroupStyle} */ - (Object.assign({}, defaultGroupStyle, {useFirstLineForOverview: true})); + (Object.assign({useFirstLineForOverview: true}, defaultGroupStyle)); this._interactionsHeaderLevel2 = /** @type {!PerfUI.FlameChart.GroupStyle} */ (Object.assign({}, defaultGroupStyle, {padding: 2, nestingLevel: 1})); @@ -161,8 +158,6 @@ this._asyncColorByInteractionPhase = new Map(); /** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */ this._extensionInfo = []; - /** @type {!Map<!TimelineModel.TimelineFrame, ?Promise<?Image>>} */ - this._frameImageCache = new Map(); } /** @@ -191,6 +186,7 @@ this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary; this._currentLevel = 0; + this._appendHeader(Common.UIString('Frames'), this._staticHeader); this._appendFrameBars(this._performanceModel.frames()); this._appendHeader(Common.UIString('Interactions'), this._interactionsHeaderLevel1); @@ -443,18 +439,14 @@ * @param {!Array.<!TimelineModel.TimelineFrame>} frames */ _appendFrameBars(frames) { - var hasFilmStrtip = !!this._performanceModel.filmStripModel().frames().length; - this._framesHeader.collapsible = hasFilmStrtip; - this._appendHeader(Common.UIString('Frames'), this._framesHeader); - this._frameGroup = this._timelineData.groups.peekLast(); var style = Timeline.TimelineUIUtils.markerStyleForFrame(); this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartEntryType.Frame; - for (var frame of frames) { + for (var i = 0; i < frames.length; ++i) { this._markers.push(new Timeline.TimelineFlameChartMarker( - frame.startTime, frame.startTime - this._model.minimumRecordTime(), style)); - this._appendFrame(frame); + frames[i].startTime, frames[i].startTime - this._model.minimumRecordTime(), style)); + this._appendFrame(frames[i]); } - this._currentLevel += hasFilmStrtip ? this._expandedFrameBarHeight : 1; + ++this._currentLevel; } /** @@ -558,66 +550,6 @@ } /** - * @param {number} entryIndex - * @param {!CanvasRenderingContext2D} context - * @param {?string} text - * @param {number} barX - * @param {number} barY - * @param {number} barWidth - * @param {number} barHeight - * @return {!Promise} - */ - async _drawFrame(entryIndex, context, text, barX, barY, barWidth, barHeight) { - var /** @const */ hPadding = 1; - var frame = /** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex]); - barX += hPadding; - barWidth -= 2 * hPadding; - context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1'); - context.fillRect(barX, barY, barWidth, barHeight); - - var imagePromise; - if (this._frameImageCache.has(frame)) { - imagePromise = this._frameImageCache.get(frame); - } else { - var modelFrame = Timeline.TimelineUIUtils.filmStripModelFrame(this._performanceModel.filmStripModel(), frame); - imagePromise = modelFrame && - modelFrame.imageDataPromise().then(data => UI.loadImage(data ? 'data:image/jpg;base64,' + data : '')); - this._frameImageCache.set(frame, imagePromise); - } - var image = await imagePromise; - // ---------------- ASYNC ---------------- - var maxTextWidth = barWidth; - if (image) { - var imageHeight = barHeight; - var imageY = barY; - if (this._frameGroup.expanded) { - imageHeight *= (this._expandedFrameBarHeight - 1); - imageY += barHeight; - } - var scale = imageHeight / image.naturalHeight; - var imageWidth = image.naturalWidth * scale; - if (!this._frameGroup.expanded) - maxTextWidth = Math.max(0, barWidth - imageWidth); - context.save(); - context.beginPath(); - context.rect(barX, imageY, barWidth, imageHeight); - context.clip(); - context.drawImage(image, barX + barWidth - imageWidth, imageY, imageWidth, imageHeight); - context.restore(); - } - - var frameDurationText = Number.preciseMillisToString(frame.duration, 1); - var textWidth = context.measureText(frameDurationText).width; - if (textWidth <= maxTextWidth) { - var font = this.entryFont(entryIndex); - if (font) - context.font = font; - context.fillStyle = this.textColor(entryIndex); - context.fillText(frameDurationText, barX + (maxTextWidth - textWidth) / 2, barY + barHeight - 4); - } - } - - /** * @override * @param {number} entryIndex * @param {!CanvasRenderingContext2D} context @@ -634,7 +566,21 @@ var data = this._entryData[entryIndex]; var type = this._entryType(entryIndex); if (type === Timeline.TimelineFlameChartEntryType.Frame) { - this._drawFrame(entryIndex, context, text, barX, barY, barWidth, barHeight); + var /** @const */ vPadding = 1; + var /** @const */ hPadding = 1; + var frame = /** {!TimelineModel.TimelineFrame} */ (data); + barX += hPadding; + barWidth -= 2 * hPadding; + barY += vPadding; + barHeight -= 2 * vPadding + 1; + context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1'); + context.fillRect(barX, barY, barWidth, barHeight); + var frameDurationText = Number.preciseMillisToString(frame.duration, 1); + var textWidth = context.measureText(frameDurationText).width; + if (barWidth >= textWidth) { + context.fillStyle = this.textColor(entryIndex); + context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, barY + barHeight - 3); + } return true; }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePaintProfilerView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePaintProfilerView.js index 3b28a01..e5e86d9 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePaintProfilerView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePaintProfilerView.js
@@ -32,8 +32,8 @@ this._pendingSnapshot = null; /** @type {?SDK.TracingModel.Event} */ this._event = null; - /** @type {?SDK.Target} */ - this._target = null; + /** @type {?SDK.PaintProfilerModel} */ + this._paintProfilerModel = null; /** @type {?SDK.PaintProfilerSnapshot} */ this._lastLoadedSnapshot = null; } @@ -59,13 +59,13 @@ } /** - * @param {!SDK.Target} target + * @param {!SDK.PaintProfilerModel} paintProfilerModel * @param {!SDK.TracingModel.Event} event * @return {boolean} */ - setEvent(target, event) { + setEvent(paintProfilerModel, event) { this._releaseSnapshot(); - this._target = target; + this._paintProfilerModel = paintProfilerModel; this._pendingSnapshot = null; this._event = event; @@ -85,7 +85,7 @@ } _update() { - this._logTreeView.setCommandLog(null, []); + this._logTreeView.setCommandLog([]); this._paintProfilerView.setSnapshotAndLog(null, [], null); var snapshotPromise; @@ -93,10 +93,9 @@ snapshotPromise = Promise.resolve({rect: null, snapshot: this._pendingSnapshot}); } else if (this._event.name === TimelineModel.TimelineModel.RecordType.Paint) { var picture = TimelineModel.TimelineData.forEvent(this._event).picture; - snapshotPromise = - picture.objectPromise() - .then(data => SDK.PaintProfilerSnapshot.load(/** @type {!SDK.Target} */ (this._target), data['skp64'])) - .then(snapshot => snapshot && {rect: null, snapshot: snapshot}); + snapshotPromise = picture.objectPromise() + .then(data => this._paintProfilerModel.loadSnapshot(data['skp64'])) + .then(snapshot => snapshot && {rect: null, snapshot: snapshot}); } else if (this._event.name === TimelineModel.TimelineModel.RecordType.RasterTask) { snapshotPromise = this._frameModel.rasterTilePromise(this._event); } else { @@ -122,7 +121,7 @@ * @this {Timeline.TimelinePaintProfilerView} */ function onCommandLogDone(snapshot, clipRect, log) { - this._logTreeView.setCommandLog(snapshot.target(), log || []); + this._logTreeView.setCommandLog(log || []); this._paintProfilerView.setSnapshotAndLog(snapshot, log || [], clipRect); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js index 3a8ec1a4..5da484d7 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -1046,13 +1046,14 @@ */ static _buildRangeStatsCacheIfNeeded(model) { var tasks = model.mainThreadTasks(); - if (tasks.length && tasks[0][Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol]) + var filter = Timeline.TimelineUIUtils._filterForStats(); + var firstTask = tasks.find(filter); + if (!firstTask || firstTask[Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol]) return; var aggregatedStats = {}; var ownTimes = []; TimelineModel.TimelineModel.forEachEvent( - model.mainThreadEvents(), onStartEvent, onEndEvent, undefined, undefined, undefined, - Timeline.TimelineUIUtils._filterForStats()); + model.mainThreadEvents(), onStartEvent, onEndEvent, undefined, undefined, undefined, filter); /** * @param {!SDK.TracingModel.Event} e @@ -1819,21 +1820,6 @@ trimAt = 30; return url.startsWith('about:') ? `"${frame.name.trimMiddle(trimAt)}"` : frame.url.trimEnd(trimAt); } - - /** - * @param {!SDK.FilmStripModel} filmStripModel - * @param {!TimelineModel.TimelineFrame} frame - * @return {?SDK.FilmStripModel.Frame} - */ - static filmStripModelFrame(filmStripModel, frame) { - var screenshotTime = frame.idle ? - frame.startTime : - frame.endTime; // For idle frames, look at the state at the beginning of the frame. - var filmStripFrame = filmStripModel.frameByTimestamp(screenshotTime); - if (filmStripFrame && filmStripFrame.timestamp - frame.endTime > 10) - filmStripFrame = null; - return filmStripFrame; - } }; /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js index 26792154..5351a44 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js
@@ -505,10 +505,11 @@ * @return !Promise<?{rect: !Array<number>, snapshot: !SDK.PaintProfilerSnapshot}>} */ snapshotPromise() { + var paintProfilerModel = this._target && this._target.model(SDK.PaintProfilerModel); return this.picturePromise().then(picture => { - if (!picture || !this._target) + if (!picture || !paintProfilerModel) return null; - return SDK.PaintProfilerSnapshot.load(this._target, picture.serializedPicture) + return paintProfilerModel.loadSnapshot(picture.serializedPicture) .then(snapshot => snapshot ? {rect: picture.rect, snapshot: snapshot} : null); }); }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TracingLayerTree.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TracingLayerTree.js index 37cca119..580a407 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TracingLayerTree.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TracingLayerTree.js
@@ -37,6 +37,7 @@ super(target); /** @type {!Map.<string, !TimelineModel.TracingLayerTile>} */ this._tileById = new Map(); + this._paintProfilerModel = target && target.model(SDK.PaintProfilerModel); } /** @@ -129,7 +130,7 @@ if (layer) layer._reset(payload); else - layer = new TimelineModel.TracingLayer(this.target(), payload); + layer = new TimelineModel.TracingLayer(this._paintProfilerModel, payload); this._layersById[payload.layer_id] = layer; if (payload.owner_node) layer._setNode(this.backendNodeIdToNode().get(payload.owner_node) || null); @@ -160,11 +161,11 @@ */ TimelineModel.TracingLayer = class { /** + * @param {?SDK.PaintProfilerModel} paintProfilerModel * @param {!TimelineModel.TracingLayerPayload} payload - * @param {?SDK.Target} target */ - constructor(target, payload) { - this._target = target; + constructor(paintProfilerModel, payload) { + this._paintProfilerModel = paintProfilerModel; this._reset(payload); } @@ -387,14 +388,14 @@ var fragments = pictures.filter(picture => picture && rectsOverlap(picture.rect, targetRect)) .map(picture => ({x: picture.rect[0], y: picture.rect[1], picture: picture.serializedPicture})); - if (!fragments.length || !this._target) + if (!fragments.length || !this._paintProfilerModel) return null; var x0 = fragments.reduce((min, item) => Math.min(min, item.x), Infinity); var y0 = fragments.reduce((min, item) => Math.min(min, item.y), Infinity); // Rect is in layer content coordinates, make it relative to picture by offsetting to the top left corner. var rect = {x: targetRect[0] - x0, y: targetRect[1] - y0, width: targetRect[2], height: targetRect[3]}; - return SDK.PaintProfilerSnapshot.loadFromFragments(this._target, fragments) - .then(snapshot => snapshot ? {rect: rect, snapshot: snapshot} : null); + return this._paintProfilerModel.loadSnapshotFromFragments(fragments).then( + snapshot => snapshot ? {rect: rect, snapshot: snapshot} : null); }); /**
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn index 6d2f39e7..191d324 100644 --- a/third_party/WebKit/Source/modules/BUILD.gn +++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -274,6 +274,7 @@ "indexeddb/MockWebIDBDatabase.h", "media_controls/MediaControlsImplTest.cpp", "media_controls/MediaControlsOrientationLockDelegateTest.cpp", + "media_controls/MediaControlsRotateToFullscreenDelegateTest.cpp", "mediastream/MediaConstraintsTest.cpp", "notifications/NotificationDataTest.cpp", "notifications/NotificationImageLoaderTest.cpp",
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp index c8784980..4e9fe8e 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp
@@ -381,6 +381,7 @@ options.blob_info = &blob_info; options.write_wasm_to_stream = ExecutionContext::From(script_state)->IsSecureContext(); + options.for_storage = true; RefPtr<SerializedScriptValue> serialized_value = SerializedScriptValue::Serialize(isolate, value.V8Value(), options, exception_state);
diff --git a/third_party/WebKit/Source/modules/media_controls/BUILD.gn b/third_party/WebKit/Source/modules/media_controls/BUILD.gn index c51c6ff3..4c94886 100644 --- a/third_party/WebKit/Source/modules/media_controls/BUILD.gn +++ b/third_party/WebKit/Source/modules/media_controls/BUILD.gn
@@ -12,6 +12,8 @@ "MediaControlsMediaEventListener.h", "MediaControlsOrientationLockDelegate.cpp", "MediaControlsOrientationLockDelegate.h", + "MediaControlsRotateToFullscreenDelegate.cpp", + "MediaControlsRotateToFullscreenDelegate.h", "MediaControlsWindowEventListener.cpp", "MediaControlsWindowEventListener.h", "elements/MediaControlCastButtonElement.cpp",
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp index a6289db..a85e906 100644 --- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -45,6 +45,7 @@ #include "core/layout/LayoutTheme.h" #include "modules/media_controls/MediaControlsMediaEventListener.h" #include "modules/media_controls/MediaControlsOrientationLockDelegate.h" +#include "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h" #include "modules/media_controls/MediaControlsWindowEventListener.h" #include "modules/media_controls/elements/MediaControlCastButtonElement.h" #include "modules/media_controls/elements/MediaControlCurrentTimeDisplayElement.h" @@ -225,6 +226,7 @@ WTF::Bind(&MediaControlsImpl::HideAllMenus, WrapWeakPersistent(this)))), orientation_lock_delegate_(nullptr), + rotate_to_fullscreen_delegate_(nullptr), hide_media_controls_timer_( TaskRunnerHelper::Get(TaskType::kUnspecedTimer, &media_element.GetDocument()), @@ -252,9 +254,18 @@ controls->InitializeControls(); controls->Reset(); - // Initialize the orientation lock when going fullscreen feature. - if (RuntimeEnabledFeatures::videoFullscreenOrientationLockEnabled() && + // RotateToFullscreen and FullscreenOrientationLock are not yet compatible + // so enabling RotateToFullscreen disables FullscreenOrientationLock. + // TODO(johnme): Make it possible to use both features simultaneously. + if (RuntimeEnabledFeatures::videoRotateToFullscreenEnabled() && media_element.IsHTMLVideoElement()) { + // Initialize the rotate-to-fullscreen feature. + controls->rotate_to_fullscreen_delegate_ = + new MediaControlsRotateToFullscreenDelegate( + toHTMLVideoElement(media_element)); + } else if (RuntimeEnabledFeatures::videoFullscreenOrientationLockEnabled() && + media_element.IsHTMLVideoElement()) { + // Initialize the orientation lock when going fullscreen feature. controls->orientation_lock_delegate_ = new MediaControlsOrientationLockDelegate( toHTMLVideoElement(media_element)); @@ -408,6 +419,8 @@ media_event_listener_->Attach(); if (orientation_lock_delegate_) orientation_lock_delegate_->Attach(); + if (rotate_to_fullscreen_delegate_) + rotate_to_fullscreen_delegate_->Attach(); if (!resize_observer_) { resize_observer_ = @@ -430,6 +443,8 @@ media_event_listener_->Detach(); if (orientation_lock_delegate_) orientation_lock_delegate_->Detach(); + if (rotate_to_fullscreen_delegate_) + rotate_to_fullscreen_delegate_->Detach(); resize_observer_.Clear(); } @@ -1130,6 +1145,7 @@ visitor->Trace(media_event_listener_); visitor->Trace(window_event_listener_); visitor->Trace(orientation_lock_delegate_); + visitor->Trace(rotate_to_fullscreen_delegate_); MediaControls::Trace(visitor); HTMLDivElement::Trace(visitor); }
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h index b14b75ee..e842e4ae 100644 --- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
@@ -36,6 +36,7 @@ class Event; class MediaControlsMediaEventListener; class MediaControlsOrientationLockDelegate; +class MediaControlsRotateToFullscreenDelegate; class MediaControlsWindowEventListener; class MediaControlCastButtonElement; class MediaControlCurrentTimeDisplayElement; @@ -146,6 +147,7 @@ // For tests. friend class MediaControlsOrientationLockDelegateTest; + friend class MediaControlsRotateToFullscreenDelegateTest; friend class MediaControlsImplTest; // Need to be members of MediaControls for private member access. @@ -245,6 +247,8 @@ Member<MediaControlsMediaEventListener> media_event_listener_; Member<MediaControlsWindowEventListener> window_event_listener_; Member<MediaControlsOrientationLockDelegate> orientation_lock_delegate_; + Member<MediaControlsRotateToFullscreenDelegate> + rotate_to_fullscreen_delegate_; TaskRunnerTimer<MediaControlsImpl> hide_media_controls_timer_; unsigned hide_timer_behavior_flags_;
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegate.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegate.h index 414a3d48..b4d77675 100644 --- a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegate.h +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegate.h
@@ -16,8 +16,8 @@ // MediaControlsOrientationLockDelegate is implementing the orientation lock // feature when a <video> is fullscreen. It is meant to be created by -// `MediaControls` when the feature applies. Once created, it will use events to -// change state. +// `MediaControlsImpl` when the feature applies. Once created, it will use +// events to change state. // // The different states of the class are: // - PendingFullscreen: the object is created and is waiting for the associated @@ -42,11 +42,11 @@ public: explicit MediaControlsOrientationLockDelegate(HTMLVideoElement&); - // Called by MediaControls when the HTMLMediaElement is added to a document + // Called by MediaControlsImpl when the HTMLMediaElement is added to a // document. All event listeners should be added. void Attach(); - // Called by MediaControls when the HTMLMediaElement is no longer in the + // Called by MediaControlsImpl when the HTMLMediaElement is no longer in the // document. All event listeners should be removed in order to prepare the // object to be garbage collected. void Detach(); @@ -92,7 +92,7 @@ // In other words, whether the orientation was locked. bool should_unlock_orientation_ = false; - // `m_videoElement` owns MediaControls that owns |this|. + // `video_element_` owns MediaControlsImpl that owns |this|. Member<HTMLVideoElement> video_element_; };
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp index c2c6a10..832dd94 100644 --- a/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsOrientationLockDelegateTest.cpp
@@ -56,7 +56,7 @@ HTMLMediaElement&, const WebMediaPlayerSource&, WebMediaPlayerClient*) override { - return WTF::WrapUnique(new MockVideoWebMediaPlayer()); + return WTF::MakeUnique<MockVideoWebMediaPlayer>(); } };
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp new file mode 100644 index 0000000..adee413 --- /dev/null +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp
@@ -0,0 +1,233 @@ +// 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 "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h" + +#include "core/dom/DocumentUserGestureToken.h" +#include "core/dom/ElementVisibilityObserver.h" +#include "core/dom/Fullscreen.h" +#include "core/events/Event.h" +#include "core/frame/LocalDOMWindow.h" +#include "core/html/HTMLVideoElement.h" +#include "core/page/ChromeClient.h" +#include "modules/media_controls/MediaControlsImpl.h" +#include "platform/UserGestureIndicator.h" +#include "public/platform/WebScreenInfo.h" + +namespace blink { + +namespace { + +// Videos must be at least this big in both dimensions to qualify. +constexpr unsigned kMinSize = 200; + +// At least this fraction of the video must be visible. +constexpr float kVisibilityThreshold = 0.75; + +} // anonymous namespace + +MediaControlsRotateToFullscreenDelegate:: + MediaControlsRotateToFullscreenDelegate(HTMLVideoElement& video) + : EventListener(kCPPEventListenerType), video_element_(video) {} + +void MediaControlsRotateToFullscreenDelegate::Attach() { + DCHECK(video_element_->isConnected()); + + LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow(); + if (!dom_window) + return; + + video_element_->addEventListener(EventTypeNames::play, this, true); + video_element_->addEventListener(EventTypeNames::pause, this, true); + + // Listen to two different fullscreen events in order to make sure the new and + // old APIs are handled. + video_element_->addEventListener(EventTypeNames::webkitfullscreenchange, this, + true); + video_element_->GetDocument().addEventListener( + EventTypeNames::fullscreenchange, this, true); + + current_screen_orientation_ = ComputeScreenOrientation(); + // TODO(johnme): Check this is battery efficient (note that this doesn't need + // to receive events for 180 deg rotations). + dom_window->addEventListener(EventTypeNames::orientationchange, this, false); +} + +void MediaControlsRotateToFullscreenDelegate::Detach() { + DCHECK(!video_element_->isConnected()); + + if (visibility_observer_) { + // TODO(johnme): Should I also call Stop in a prefinalizer? + visibility_observer_->Stop(); + visibility_observer_ = nullptr; + is_visible_ = false; + } + + video_element_->removeEventListener(EventTypeNames::play, this, true); + video_element_->removeEventListener(EventTypeNames::pause, this, true); + + video_element_->removeEventListener(EventTypeNames::webkitfullscreenchange, + this, true); + video_element_->GetDocument().removeEventListener( + EventTypeNames::fullscreenchange, this, true); + + LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow(); + if (!dom_window) + return; + dom_window->removeEventListener(EventTypeNames::orientationchange, this, + false); +} + +bool MediaControlsRotateToFullscreenDelegate::operator==( + const EventListener& other) const { + return this == &other; +} + +void MediaControlsRotateToFullscreenDelegate::handleEvent( + ExecutionContext* execution_context, + Event* event) { + if (event->type() == EventTypeNames::play || + event->type() == EventTypeNames::pause || + event->type() == EventTypeNames::fullscreenchange || + event->type() == EventTypeNames::webkitfullscreenchange) { + OnStateChange(); + return; + } + if (event->type() == EventTypeNames::orientationchange) { + OnScreenOrientationChange(); + return; + } + + NOTREACHED(); +} + +void MediaControlsRotateToFullscreenDelegate::OnStateChange() { + // TODO(johnme): Check this aggressive disabling doesn't lead to race + // conditions where we briefly don't know if the video is visible. + bool needs_visibility_observer = + !video_element_->paused() && !video_element_->IsFullscreen(); + DVLOG(3) << __func__ << " " << !!visibility_observer_ << " -> " + << needs_visibility_observer; + + if (needs_visibility_observer && !visibility_observer_) { + visibility_observer_ = new ElementVisibilityObserver( + video_element_, + WTF::Bind(&MediaControlsRotateToFullscreenDelegate::OnVisibilityChange, + WrapWeakPersistent(this))); + visibility_observer_->Start(kVisibilityThreshold); + } else if (!needs_visibility_observer && visibility_observer_) { + visibility_observer_->Stop(); + visibility_observer_ = nullptr; + is_visible_ = false; + } +} + +void MediaControlsRotateToFullscreenDelegate::OnVisibilityChange( + bool is_visible) { + DVLOG(3) << __func__ << " " << is_visible_ << " -> " << is_visible; + is_visible_ = is_visible; +} + +void MediaControlsRotateToFullscreenDelegate::OnScreenOrientationChange() { + SimpleOrientation previous_screen_orientation = current_screen_orientation_; + current_screen_orientation_ = ComputeScreenOrientation(); + DVLOG(3) << __func__ << " " << static_cast<int>(previous_screen_orientation) + << " -> " << static_cast<int>(current_screen_orientation_); + + // Only enable if native media controls are used. + if (!video_element_->ShouldShowControls()) + return; + + // Don't enter/exit fullscreen if some other element is fullscreen. + Element* fullscreen_element = + Fullscreen::CurrentFullScreenElementFrom(video_element_->GetDocument()); + if (fullscreen_element && fullscreen_element != video_element_) + return; + + // To enter fullscreen, video must be visible and playing. + // TODO(johnme): If orientation changes whilst this tab is in the background, + // we'll get an orientationchange event when this tab next becomes active. + // Check that those events don't trigger rotate-to-fullscreen. + if (!video_element_->IsFullscreen() && + (!is_visible_ || video_element_->paused())) { + return; + } + + // Ignore (unexpected) events where we have incomplete information. + if (previous_screen_orientation == SimpleOrientation::kUnknown || + current_screen_orientation_ == SimpleOrientation::kUnknown) { + return; + } + + // Ignore 180 degree rotations between PortraitPrimary and PortraitSecondary, + // or between LandscapePrimary and LandscapeSecondary. + if (previous_screen_orientation == current_screen_orientation_) + return; + + SimpleOrientation video_orientation = ComputeVideoOrientation(); + + // Ignore videos that are square/small/etc. + if (video_orientation == SimpleOrientation::kUnknown) + return; + + MediaControlsImpl& media_controls = + *static_cast<MediaControlsImpl*>(video_element_->GetMediaControls()); + + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&video_element_->GetDocument())); + + bool should_be_fullscreen = + current_screen_orientation_ == video_orientation; + if (should_be_fullscreen && !video_element_->IsFullscreen()) + media_controls.EnterFullscreen(); + else if (!should_be_fullscreen && video_element_->IsFullscreen()) + media_controls.ExitFullscreen(); + } +} + +MediaControlsRotateToFullscreenDelegate::SimpleOrientation +MediaControlsRotateToFullscreenDelegate::ComputeVideoOrientation() const { + if (video_element_->getReadyState() == HTMLMediaElement::kHaveNothing) + return SimpleOrientation::kUnknown; + + const unsigned width = video_element_->videoWidth(); + const unsigned height = video_element_->videoHeight(); + + if (width < kMinSize || height < kMinSize) + return SimpleOrientation::kUnknown; // Too small, ignore this video. + + if (width >= height) + return SimpleOrientation::kLandscape; // Includes square videos. + return SimpleOrientation::kPortrait; +} + +MediaControlsRotateToFullscreenDelegate::SimpleOrientation +MediaControlsRotateToFullscreenDelegate::ComputeScreenOrientation() const { + Frame* frame = video_element_->GetDocument().GetFrame(); + if (!frame) + return SimpleOrientation::kUnknown; + + switch (frame->GetChromeClient().GetScreenInfo().orientation_type) { + case kWebScreenOrientationPortraitPrimary: + case kWebScreenOrientationPortraitSecondary: + return SimpleOrientation::kPortrait; + case kWebScreenOrientationLandscapePrimary: + case kWebScreenOrientationLandscapeSecondary: + return SimpleOrientation::kLandscape; + case kWebScreenOrientationUndefined: + return SimpleOrientation::kUnknown; + } + + NOTREACHED(); + return SimpleOrientation::kUnknown; +} + +DEFINE_TRACE(MediaControlsRotateToFullscreenDelegate) { + EventListener::Trace(visitor); + visitor->Trace(video_element_); + visitor->Trace(visibility_observer_); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.h new file mode 100644 index 0000000..5146edf --- /dev/null +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.h
@@ -0,0 +1,69 @@ +// 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 MediaControlsRotateToFullscreenDelegate_h +#define MediaControlsRotateToFullscreenDelegate_h + +#include "core/events/EventListener.h" +#include "modules/ModulesExport.h" + +namespace blink { + +class HTMLVideoElement; +class ElementVisibilityObserver; + +// MediaControlsRotateToFullscreenDelegate automatically enters and exits +// fullscreen when the device is rotated whilst watching a <video>. It is meant +// to be created by `MediaControlsImpl` when the feature applies. Once created, +// it will listen for events. +class MediaControlsRotateToFullscreenDelegate final : public EventListener { + public: + explicit MediaControlsRotateToFullscreenDelegate(HTMLVideoElement&); + + // Called by MediaControlsImpl when the HTMLMediaElement is added to a + // document. All event listeners should be added. + void Attach(); + + // Called by MediaControlsImpl when the HTMLMediaElement is no longer in the + // document. All event listeners should be removed in order to prepare the + // object to be garbage collected. + void Detach(); + + // EventListener implementation. + bool operator==(const EventListener&) const override; + + DECLARE_VIRTUAL_TRACE(); + + private: + friend class MediaControlsRotateToFullscreenDelegateTest; + + // Represents either screen orientation or video aspect ratio. + enum class SimpleOrientation { kPortrait, kLandscape, kUnknown }; + + // EventListener implementation. + void handleEvent(ExecutionContext*, Event*) override; + + void OnStateChange(); + void OnVisibilityChange(bool is_visible); + void OnScreenOrientationChange(); + + MODULES_EXPORT SimpleOrientation ComputeVideoOrientation() const; + SimpleOrientation ComputeScreenOrientation() const; + + SimpleOrientation current_screen_orientation_ = SimpleOrientation::kUnknown; + + // Only valid when visibility_observer_ is active and the first + // OnVisibilityChanged has been received; otherwise assume video is hidden. + bool is_visible_ = false; + + // This is null whenever we're not listening. + Member<ElementVisibilityObserver> visibility_observer_ = nullptr; + + // `video_element_` owns MediaControlsImpl that owns |this|. + Member<HTMLVideoElement> video_element_; +}; + +} // namespace blink + +#endif // MediaControlsRotateToFullscreenDelegate_h
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegateTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegateTest.cpp new file mode 100644 index 0000000..3e831ea --- /dev/null +++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegateTest.cpp
@@ -0,0 +1,663 @@ +// 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 "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h" + +#include "core/HTMLNames.h" +#include "core/css/CSSStyleDeclaration.h" +#include "core/dom/Document.h" +#include "core/dom/DocumentUserGestureToken.h" +#include "core/dom/Fullscreen.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalDOMWindow.h" +#include "core/frame/Settings.h" +#include "core/html/HTMLAudioElement.h" +#include "core/html/HTMLVideoElement.h" +#include "core/loader/EmptyClients.h" +#include "core/testing/DummyPageHolder.h" +#include "modules/media_controls/MediaControlsImpl.h" +#include "platform/UserGestureIndicator.h" +#include "platform/testing/EmptyWebMediaPlayer.h" +#include "platform/testing/UnitTestHelpers.h" +#include "platform/wtf/text/AtomicString.h" +#include "public/platform/WebSize.h" +#include "public/platform/modules/screen_orientation/WebScreenOrientationType.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::Return; + +namespace blink { + +using namespace HTMLNames; + +namespace { + +class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { + public: + // ChromeClient overrides: + bool HasVideo() const override { return true; } + + MOCK_CONST_METHOD0(NaturalSize, WebSize()); +}; + +class MockChromeClient : public EmptyChromeClient { + public: + // ChromeClient overrides: + void EnterFullscreen(LocalFrame& frame) override { + Fullscreen::From(*frame.GetDocument()).DidEnterFullscreen(); + } + void ExitFullscreen(LocalFrame& frame) override { + Fullscreen::From(*frame.GetDocument()).DidExitFullscreen(); + } + + MOCK_CONST_METHOD0(GetScreenInfo, WebScreenInfo()); +}; + +class StubLocalFrameClient : public EmptyLocalFrameClient { + public: + static StubLocalFrameClient* Create() { return new StubLocalFrameClient; } + + std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer( + HTMLMediaElement&, + const WebMediaPlayerSource&, + WebMediaPlayerClient*) override { + return WTF::MakeUnique<MockVideoWebMediaPlayer>(); + } +}; + +} // anonymous namespace + +class MediaControlsRotateToFullscreenDelegateTest : public ::testing::Test { + protected: + using SimpleOrientation = + MediaControlsRotateToFullscreenDelegate::SimpleOrientation; + + void SetUp() override { + previous_video_rotate_to_fullscreen_value_ = + RuntimeEnabledFeatures::videoRotateToFullscreenEnabled(); + RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(true); + + chrome_client_ = new MockChromeClient(); + + Page::PageClients clients; + FillWithEmptyClients(clients); + clients.chrome_client = chrome_client_.Get(); + + page_holder_ = DummyPageHolder::Create(IntSize(800, 600), &clients, + StubLocalFrameClient::Create()); + + video_ = HTMLVideoElement::Create(GetDocument()); + GetVideo().setAttribute(controlsAttr, g_empty_atom); + // Most tests should call GetDocument().body()->AppendChild(&GetVideo()); + // This is not done automatically, so that tests control timing of `Attach`. + } + + void TearDown() override { + RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled( + previous_video_rotate_to_fullscreen_value_); + } + + static bool HasDelegate(const MediaControls& media_controls) { + return !!static_cast<const MediaControlsImpl*>(&media_controls) + ->rotate_to_fullscreen_delegate_; + } + + static bool HasOrientationLockDelegate(const MediaControls& media_controls) { + return !!static_cast<const MediaControlsImpl*>(&media_controls) + ->orientation_lock_delegate_; + } + + void SimulateVideoReadyState(HTMLMediaElement::ReadyState state) { + GetVideo().SetReadyState(state); + } + + SimpleOrientation ObservedScreenOrientation() const { + return GetMediaControls() + .rotate_to_fullscreen_delegate_->current_screen_orientation_; + } + + SimpleOrientation ComputeVideoOrientation() const { + return GetMediaControls() + .rotate_to_fullscreen_delegate_->ComputeVideoOrientation(); + } + + bool IsObservingVisibility() const { + return GetMediaControls() + .rotate_to_fullscreen_delegate_->visibility_observer_; + } + + bool ObservedVisibility() const { + return GetMediaControls().rotate_to_fullscreen_delegate_->is_visible_; + } + + void DisableControls() { + // If scripts are not enabled, controls will always be shown. + page_holder_->GetFrame().GetSettings()->SetScriptEnabled(true); + + GetVideo().removeAttribute(controlsAttr); + } + + void DispatchEvent(EventTarget& target, const AtomicString& type) { + target.DispatchEvent(Event::Create(type)); + } + + void InitScreenAndVideo(WebScreenOrientationType initial_screen_orientation, + WebSize video_size); + + void PlayVideo(); + + void UpdateVisibilityObserver() { + // Let IntersectionObserver update. + GetDocument().View()->UpdateAllLifecyclePhases(); + testing::RunPendingTasks(); + } + + void RotateTo(WebScreenOrientationType new_screen_orientation); + + MockChromeClient& GetChromeClient() const { return *chrome_client_; } + LocalDOMWindow& GetWindow() const { return *GetDocument().domWindow(); } + Document& GetDocument() const { return page_holder_->GetDocument(); } + HTMLVideoElement& GetVideo() const { return *video_; } + MediaControlsImpl& GetMediaControls() const { + return *static_cast<MediaControlsImpl*>(GetVideo().GetMediaControls()); + } + MockVideoWebMediaPlayer& GetWebMediaPlayer() const { + return *static_cast<MockVideoWebMediaPlayer*>( + GetVideo().GetWebMediaPlayer()); + } + + private: + bool previous_video_rotate_to_fullscreen_value_; + Persistent<MockChromeClient> chrome_client_; + std::unique_ptr<DummyPageHolder> page_holder_; + Persistent<HTMLVideoElement> video_; +}; + +void MediaControlsRotateToFullscreenDelegateTest::InitScreenAndVideo( + WebScreenOrientationType initial_screen_orientation, + WebSize video_size) { + // Set initial screen orientation (called by `Attach` during `AppendChild`). + WebScreenInfo screen_info; + screen_info.orientation_type = initial_screen_orientation; + EXPECT_CALL(GetChromeClient(), GetScreenInfo()) + .Times(1) + .WillOnce(Return(screen_info)); + + // Set up the WebMediaPlayer instance. + GetDocument().body()->AppendChild(&GetVideo()); + GetVideo().SetSrc("https://example.com"); + testing::RunPendingTasks(); + SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata); + + // Set video size. + EXPECT_CALL(GetWebMediaPlayer(), NaturalSize()) + .WillRepeatedly(Return(video_size)); +} + +void MediaControlsRotateToFullscreenDelegateTest::PlayVideo() { + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + GetVideo().Play(); + } + testing::RunPendingTasks(); +} + +void MediaControlsRotateToFullscreenDelegateTest::RotateTo( + WebScreenOrientationType new_screen_orientation) { + WebScreenInfo screen_info; + screen_info.orientation_type = new_screen_orientation; + EXPECT_CALL(GetChromeClient(), GetScreenInfo()) + .Times(1) + .WillOnce(Return(screen_info)); + DispatchEvent(GetWindow(), EventTypeNames::orientationchange); + testing::RunPendingTasks(); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, DelegateRequiresFlag) { + // SetUp turns the flag on by default. + GetDocument().body()->AppendChild(&GetVideo()); + EXPECT_TRUE(HasDelegate(GetMediaControls())); + + // No delegate when flag is off. + RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(false); + HTMLVideoElement* video = HTMLVideoElement::Create(GetDocument()); + GetDocument().body()->AppendChild(video); + EXPECT_FALSE(HasDelegate(*video->GetMediaControls())); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, DelegateRequiresVideo) { + HTMLAudioElement* audio = HTMLAudioElement::Create(GetDocument()); + GetDocument().body()->AppendChild(audio); + EXPECT_FALSE(HasDelegate(*audio->GetMediaControls())); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + OrientationLockIsMutuallyExclusive) { + // Rotate to fullscreen and fullscreen orientation lock are currently + // incompatible, so if both are enabled only one should be active. + RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(true); + RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(true); + HTMLVideoElement* video = HTMLVideoElement::Create(GetDocument()); + GetDocument().body()->AppendChild(video); + EXPECT_TRUE(HasDelegate(*video->GetMediaControls())); + EXPECT_FALSE(HasOrientationLockDelegate(*video->GetMediaControls())); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, ComputeVideoOrientation) { + // Set up the WebMediaPlayer instance. + GetDocument().body()->AppendChild(&GetVideo()); + GetVideo().SetSrc("https://example.com"); + testing::RunPendingTasks(); + + // Each `ComputeVideoOrientation` calls `NaturalSize` twice, except the first + // one where the video is not yet ready. + EXPECT_CALL(GetWebMediaPlayer(), NaturalSize()) + .Times(12) + .WillOnce(Return(WebSize(400, 400))) + .WillOnce(Return(WebSize(400, 400))) + .WillOnce(Return(WebSize(300, 200))) + .WillOnce(Return(WebSize(300, 200))) + .WillOnce(Return(WebSize(200, 300))) + .WillOnce(Return(WebSize(200, 300))) + .WillOnce(Return(WebSize(300, 199))) + .WillOnce(Return(WebSize(300, 199))) + .WillOnce(Return(WebSize(199, 300))) + .WillOnce(Return(WebSize(199, 300))) + .WillOnce(Return(WebSize(0, 0))) + .WillOnce(Return(WebSize(0, 0))); + + // Video is not yet ready. + EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation()); + + SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata); + + // 400x400 is square, which is currently treated as landscape. + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + // 300x200 is landscape. + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + // 200x300 is portrait. + EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation()); + // 300x199 is too small. + EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation()); + // 199x300 is too small. + EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation()); + // 0x0 is empty. + EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + OnlyObserveVisibilityWhenPlaying) { + // Should not initially be observing visibility. + GetDocument().body()->AppendChild(&GetVideo()); + EXPECT_FALSE(IsObservingVisibility()); + + // Should start observing visibility when played. + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + GetVideo().Play(); + } + testing::RunPendingTasks(); + EXPECT_TRUE(IsObservingVisibility()); + EXPECT_FALSE(ObservedVisibility()); + + // Should have observed visibility once compositor updates. + GetDocument().View()->UpdateAllLifecyclePhases(); + testing::RunPendingTasks(); + EXPECT_TRUE(ObservedVisibility()); + + // Should stop observing visibility when paused. + GetVideo().pause(); + testing::RunPendingTasks(); + EXPECT_FALSE(IsObservingVisibility()); + EXPECT_FALSE(ObservedVisibility()); + + // Should resume observing visibility when playback resumes. + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + GetVideo().Play(); + } + testing::RunPendingTasks(); + EXPECT_TRUE(IsObservingVisibility()); + EXPECT_FALSE(ObservedVisibility()); + + // Should have observed visibility once compositor updates. + GetDocument().View()->UpdateAllLifecyclePhases(); + testing::RunPendingTasks(); + EXPECT_TRUE(ObservedVisibility()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterSuccessPortraitToLandscape) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + EXPECT_FALSE(GetVideo().IsFullscreen()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should enter fullscreen. + EXPECT_TRUE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterSuccessLandscapeToPortrait) { + // Landscape screen, portrait video. + InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(480, 640)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + EXPECT_FALSE(GetVideo().IsFullscreen()); + + // Rotate screen to portrait. + RotateTo(kWebScreenOrientationPortraitPrimary); + + // Should enter fullscreen. + EXPECT_TRUE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterSuccessSquarePortraitToLandscape) { + // Portrait screen, square video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(400, 400)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + EXPECT_FALSE(GetVideo().IsFullscreen()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should enter fullscreen, since square videos are currently treated the same + // as landscape videos. + EXPECT_TRUE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailWrongOrientation) { + // Landscape screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to portrait. + RotateTo(kWebScreenOrientationPortraitPrimary); + + // Should not enter fullscreen since the orientation that the device was + // rotated to does not match the orientation of the video. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterFailSquareWrongOrientation) { + // Landscape screen, square video. + InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(400, 400)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to portrait. + RotateTo(kWebScreenOrientationPortraitPrimary); + + // Should not enter fullscreen since square videos are treated as landscape, + // so rotating to portrait does not match the orientation of the video. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailNoControls) { + DisableControls(); + + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen since video has no controls. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailPaused) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + EXPECT_FALSE(ObservedVisibility()); + + UpdateVisibilityObserver(); + + EXPECT_FALSE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen since video is paused. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailHidden) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Move video offscreen. + GetDocument().body()->style()->setProperty("margin-top", "-999px", "", + ASSERT_NO_EXCEPTION); + + UpdateVisibilityObserver(); + + EXPECT_FALSE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen since video is not visible. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterFail180DegreeRotation) { + // Landscape screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationLandscapeSecondary, + WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen 180 degrees to the opposite landscape (without passing via a + // portrait orientation). + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen since this is a 180 degree orientation. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailSmall) { + // Portrait screen, small landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(300, 199)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen since video is too small. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterFailDocumentFullscreen) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Simulate the webpage requesting fullscreen on some other element than the + // video (in this case document.body). + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + Fullscreen::RequestFullscreen(*GetDocument().body()); + } + testing::RunPendingTasks(); + EXPECT_TRUE(Fullscreen::IsCurrentFullScreenElement(*GetDocument().body())); + EXPECT_FALSE(GetVideo().IsFullscreen()); + + // Play video. + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen on video, since document is already fullscreen. + EXPECT_TRUE(Fullscreen::IsCurrentFullScreenElement(*GetDocument().body())); + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + ExitSuccessLandscapeFullscreenToPortraitInline) { + // Landscape screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Start in fullscreen. + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + GetMediaControls().EnterFullscreen(); + } + testing::RunPendingTasks(); + EXPECT_TRUE(GetVideo().IsFullscreen()); + + // Leave video paused (playing is not a requirement to exit fullscreen). + EXPECT_TRUE(GetVideo().paused()); + EXPECT_FALSE(ObservedVisibility()); + + // Rotate screen to portrait. + RotateTo(kWebScreenOrientationPortraitPrimary); + + // Should exit fullscreen. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + ExitSuccessPortraitFullscreenToLandscapeInline) { + // Portrait screen, portrait video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(480, 640)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation()); + + // Start in fullscreen. + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + GetMediaControls().EnterFullscreen(); + } + testing::RunPendingTasks(); + EXPECT_TRUE(GetVideo().IsFullscreen()); + + // Leave video paused (playing is not a requirement to exit fullscreen). + EXPECT_TRUE(GetVideo().paused()); + EXPECT_FALSE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should exit fullscreen. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + ExitFailDocumentFullscreen) { + // Landscape screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + // Simulate the webpage requesting fullscreen on some other element than the + // video (in this case document.body). + { + UserGestureIndicator gesture( + DocumentUserGestureToken::Create(&GetDocument())); + Fullscreen::RequestFullscreen(*GetDocument().body()); + } + testing::RunPendingTasks(); + EXPECT_TRUE(Fullscreen::IsCurrentFullScreenElement(*GetDocument().body())); + EXPECT_FALSE(GetVideo().IsFullscreen()); + + // Leave video paused (playing is not a requirement to exit fullscreen). + EXPECT_TRUE(GetVideo().paused()); + EXPECT_FALSE(ObservedVisibility()); + + // Rotate screen to portrait. + RotateTo(kWebScreenOrientationPortraitPrimary); + + // Should not exit fullscreen, since video was not the fullscreen element. + EXPECT_TRUE(Fullscreen::IsCurrentFullScreenElement(*GetDocument().body())); + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp index 553622a..55570f8 100644 --- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp +++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -9,6 +9,7 @@ #include "core/dom/FrameRequestCallback.h" #include "core/dom/ScriptedAnimationController.h" #include "core/dom/TaskRunnerHelper.h" +#include "core/frame/Frame.h" #include "core/frame/FrameView.h" #include "core/frame/ImageBitmap.h" #include "core/frame/UseCounter.h" @@ -104,8 +105,36 @@ } } +bool VRDisplay::IsPresentationFocused() { + if (!navigator_vr_) + return false; + + if (navigator_vr_->IsFocused()) + return true; + + auto doc = navigator_vr_->GetDocument(); + if (!doc) + return false; + + // Check if this is an embedded iframe without focus. If a local parent is + // focused, continue presenting. + + Frame* frame = doc->GetFrame(); + for (; frame; frame = frame->Tree().Parent()) { + if (!frame->IsLocalFrame()) + break; + auto frame_doc = ToLocalFrame(frame)->GetDocument(); + if (frame_doc && frame_doc->hasFocus()) { + DVLOG(3) << __FUNCTION__ << ": a parent frame is focused"; + return true; + } + } + + return false; +} + bool VRDisplay::getFrameData(VRFrameData* frame_data) { - if (!navigator_vr_->IsFocused() || !frame_pose_ || display_blurred_) + if (!IsPresentationFocused() || !frame_pose_ || display_blurred_) return false; if (!frame_data) @@ -747,7 +776,11 @@ } void VRDisplay::ConnectVSyncProvider() { - if (!navigator_vr_->IsFocused() || vr_v_sync_provider_.is_bound()) + DVLOG(1) << __FUNCTION__ + << ": IsPresentationFocused()=" << IsPresentationFocused() + << " vr_v_sync_provider_.is_bound()=" + << vr_v_sync_provider_.is_bound(); + if (!IsPresentationFocused() || vr_v_sync_provider_.is_bound()) return; display_->GetVRVSyncProvider(mojo::MakeRequest(&vr_v_sync_provider_)); vr_v_sync_provider_.set_connection_error_handler(ConvertToBaseCallback(
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.h b/third_party/WebKit/Source/modules/vr/VRDisplay.h index 16dead3..3fa6504 100644 --- a/third_party/WebKit/Source/modules/vr/VRDisplay.h +++ b/third_party/WebKit/Source/modules/vr/VRDisplay.h
@@ -140,6 +140,7 @@ void ConnectVSyncProvider(); void OnVSyncConnectionError(); + bool IsPresentationFocused(); ScriptedAnimationController& EnsureScriptedAnimationController(Document*); void ProcessScheduledAnimations(double timestamp); void ProcessScheduledWindowAnimations(double timestamp);
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 index f4da0052..f4eeab3 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -970,6 +970,9 @@ name: "VideoFullscreenOrientationLock", }, { + name: "VideoRotateToFullscreen", + }, + { name: "VisibilityChangeOnUnload", status: "stable", },
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index 4f4e0b6e..0aaecc29 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -474,11 +474,49 @@ return true; } +static bool EffectGroupContainsChunk( + const EffectPaintPropertyNode& group_effect, + const PaintChunk& chunk) { + const EffectPaintPropertyNode* effect = + chunk.properties.property_tree_state.Effect(); + return effect == &group_effect || + StrictChildOfAlongPath(&group_effect, effect); +} + +static bool SkipGroupIfEffectivelyInvisible( + const PaintArtifact& paint_artifact, + const EffectPaintPropertyNode& current_group, + Vector<PaintChunk>::const_iterator& chunk_it) { + // The lower bound of visibility is considered to be 0.0004f < 1/2048. With + // 10-bit color channels (only available on the newest Macs as of 2016; + // otherwise it's 8-bit), we see that an alpha of 1/2048 or less leads to a + // color output of less than 0.5 in all channels, hence not visible. + static const float kMinimumVisibleOpacity = 0.0004f; + if (current_group.Opacity() >= kMinimumVisibleOpacity || + current_group.HasDirectCompositingReasons()) { + return false; + } + + // Fast-forward to just past the end of the chunk sequence within this + // effect group. + DCHECK(EffectGroupContainsChunk(current_group, *chunk_it)); + while (++chunk_it != paint_artifact.PaintChunks().end()) { + if (!EffectGroupContainsChunk(current_group, *chunk_it)) + break; + } + return true; +} + void PaintArtifactCompositor::LayerizeGroup( const PaintArtifact& paint_artifact, Vector<PendingLayer>& pending_layers, const EffectPaintPropertyNode& current_group, Vector<PaintChunk>::const_iterator& chunk_it) { + // Skip paint chunks that are effectively invisible due to opacity and don't + // have a direct compositing reason. + if (SkipGroupIfEffectivelyInvisible(paint_artifact, current_group, chunk_it)) + return; + size_t first_layer_in_current_group = pending_layers.size(); // The worst case time complexity of the algorithm is O(pqd), where // p = the number of paint chunks.
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp index d4ff05f7..2c13bd2 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -143,6 +143,30 @@ .get(); } + void AddSimpleRectChunk(TestPaintArtifact& artifact) { + artifact + .Chunk(TransformPaintPropertyNode::Root(), + ClipPaintPropertyNode::Root(), EffectPaintPropertyNode::Root()) + .RectDrawing(FloatRect(100, 100, 200, 100), Color::kBlack); + } + + void CreateSimpleArtifactWithOpacity(TestPaintArtifact& artifact, + float opacity, + bool include_preceding_chunk, + bool include_subsequent_chunk) { + if (include_preceding_chunk) + AddSimpleRectChunk(artifact); + RefPtr<EffectPaintPropertyNode> effect = + CreateOpacityOnlyEffect(EffectPaintPropertyNode::Root(), opacity); + artifact + .Chunk(TransformPaintPropertyNode::Root(), + ClipPaintPropertyNode::Root(), effect) + .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); + if (include_subsequent_chunk) + AddSimpleRectChunk(artifact); + Update(artifact.Build()); + } + private: std::unique_ptr<PaintArtifactCompositor> paint_artifact_compositor_; scoped_refptr<base::TestSimpleTaskRunner> task_runner_; @@ -2075,4 +2099,171 @@ composited_element_ids.Contains(effect->GetCompositorElementId())); } +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, SkipChunkWithOpacityZero) { + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0, false, false); + ASSERT_EQ(0u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0, true, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0, true, true); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0, false, true); + ASSERT_EQ(1u, ContentLayerCount()); + } +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, SkipChunkWithTinyOpacity) { + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0003f, false, false); + ASSERT_EQ(0u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0003f, true, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0003f, true, true); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0003f, false, true); + ASSERT_EQ(1u, ContentLayerCount()); + } +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, + DontSkipChunkWithMinimumOpacity) { + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0004f, false, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0004f, true, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0004f, true, true); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.0004f, false, true); + ASSERT_EQ(1u, ContentLayerCount()); + } +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, + DontSkipChunkWithAboveMinimumOpacity) { + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.3f, false, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.3f, true, false); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.3f, true, true); + ASSERT_EQ(1u, ContentLayerCount()); + } + { + TestPaintArtifact artifact; + CreateSimpleArtifactWithOpacity(artifact, 0.3f, false, true); + ASSERT_EQ(1u, ContentLayerCount()); + } +} + +PassRefPtr<EffectPaintPropertyNode> CreateEffectWithOpacityAndReason( + float opacity, + CompositingReasons reason, + RefPtr<EffectPaintPropertyNode> parent = nullptr) { + return EffectPaintPropertyNode::Create( + parent ? parent : EffectPaintPropertyNode::Root(), + TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(), + kColorFilterNone, CompositorFilterOperations(), opacity, + SkBlendMode::kSrcOver, reason); +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, + DontSkipChunkWithTinyOpacityAndDirectCompositingReason) { + RefPtr<EffectPaintPropertyNode> effect = + CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonCanvas); + TestPaintArtifact artifact; + artifact + .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(), + effect) + .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); + Update(artifact.Build()); + ASSERT_EQ(1u, ContentLayerCount()); +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, + SkipChunkWithTinyOpacityAndVisibleChildEffectNode) { + RefPtr<EffectPaintPropertyNode> tinyEffect = + CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonNone); + RefPtr<EffectPaintPropertyNode> visibleEffect = + CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonNone, + tinyEffect); + TestPaintArtifact artifact; + artifact + .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(), + visibleEffect) + .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); + Update(artifact.Build()); + ASSERT_EQ(0u, ContentLayerCount()); +} + +TEST_F( + PaintArtifactCompositorTestWithPropertyTrees, + DontSkipChunkWithTinyOpacityAndVisibleChildEffectNodeWithCompositingParent) { + RefPtr<EffectPaintPropertyNode> tinyEffect = + CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonCanvas); + RefPtr<EffectPaintPropertyNode> visibleEffect = + CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonNone, + tinyEffect); + TestPaintArtifact artifact; + artifact + .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(), + visibleEffect) + .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); + Update(artifact.Build()); + ASSERT_EQ(1u, ContentLayerCount()); +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, + SkipChunkWithTinyOpacityAndVisibleChildEffectNodeWithCompositingChild) { + RefPtr<EffectPaintPropertyNode> tinyEffect = + CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonNone); + RefPtr<EffectPaintPropertyNode> visibleEffect = + CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonCanvas, + tinyEffect); + TestPaintArtifact artifact; + artifact + .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(), + visibleEffect) + .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); + Update(artifact.Build()); + ASSERT_EQ(0u, ContentLayerCount()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp index 3ee95df..820bcb8e 100644 --- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp +++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -396,6 +396,10 @@ RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(enable); } +void WebRuntimeFeatures::EnableVideoRotateToFullscreen(bool enable) { + RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(enable); +} + void WebRuntimeFeatures::EnableVideoFullscreenDetection(bool enable) { RuntimeEnabledFeatures::setVideoFullscreenDetectionEnabled(enable); }
diff --git a/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp b/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp index 9f344d0c..f97e757 100644 --- a/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp +++ b/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp
@@ -347,9 +347,10 @@ // areas from the chain have corresponding reasons. EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); + EXPECT_WHEEL_BUCKET(kIsNotStackingContextAndLCDText, 1); EXPECT_WHEEL_BUCKET(kHasBorderRadius, 1); EXPECT_WHEEL_BUCKET(kHasTransformAndLCDText, 0); - EXPECT_WHEEL_TOTAL(3); + EXPECT_WHEEL_TOTAL(4); } } // namespace
diff --git a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp index bf8143fa..821f9e3c 100644 --- a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp +++ b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
@@ -1052,7 +1052,8 @@ static const uint32_t kLCDTextRelatedReasons = MainThreadScrollingReason::kHasOpacityAndLCDText | MainThreadScrollingReason::kHasTransformAndLCDText | - MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText; + MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText | + MainThreadScrollingReason::kIsNotStackingContextAndLCDText; protected: NonCompositedMainThreadScrollingReasonTest() { @@ -1207,6 +1208,35 @@ "box-shadow", MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer); } +TEST_P(NonCompositedMainThreadScrollingReasonTest, StackingContextTest) { + GetWebViewImpl()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false); + + Document* document = GetFrame()->GetDocument(); + Element* container = document->getElementById("scroller1"); + ASSERT_TRUE(container); + + ForceFullCompositingUpdate(); + + // If a scroller contains all its children, it's not a stacking context. + PaintLayerScrollableArea* scrollable_area = + ToLayoutBoxModelObject(container->GetLayoutObject())->GetScrollableArea(); + ASSERT_TRUE(scrollable_area); + EXPECT_TRUE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() & + MainThreadScrollingReason::kIsNotStackingContextAndLCDText); + + GetWebViewImpl()->GetSettings()->SetPreferCompositingToLCDTextEnabled(true); + ForceFullCompositingUpdate(); + EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons() & + MainThreadScrollingReason::kIsNotStackingContextAndLCDText); + GetWebViewImpl()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false); + + // Adding "contain: paint" to force a stacking context leads to promotion. + container->setAttribute("style", "contain: paint", ASSERT_NO_EXCEPTION); + ForceFullCompositingUpdate(); + + EXPECT_FALSE(scrollable_area->GetNonCompositedMainThreadScrollingReasons()); +} + TEST_P(NonCompositedMainThreadScrollingReasonTest, CompositedWithLCDTextRelatedReasonsTest) { // With "will-change:transform" we composite elements with
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h index 2144839a..7271f4f 100644 --- a/third_party/WebKit/public/web/WebRuntimeFeatures.h +++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -147,6 +147,7 @@ BLINK_EXPORT static void EnableSendBeaconThrowForBlobWithNonSimpleType(bool); BLINK_EXPORT static void EnableBackgroundVideoTrackOptimization(bool); BLINK_EXPORT static void EnableVideoFullscreenOrientationLock(bool); + BLINK_EXPORT static void EnableVideoRotateToFullscreen(bool); BLINK_EXPORT static void EnableVideoFullscreenDetection(bool); BLINK_EXPORT static void EnableMediaControlsOverlayPlayButton(bool);
diff --git a/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt b/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt index 00c3e370..e9c4d4bd 100644 --- a/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt +++ b/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt
@@ -4,3 +4,4 @@ v1.2 5400db0e25a24e0df9635ab268ef1058a60dfec2 v1.3 db5eaf6e83a10e809b96375212d5c9dbbe517624 v1.4 9afe32eb4676d4bcceae81605a3be6aa0e5be3d5 +v1.5 a02e2f95aa6f741f2be0ae03a4829e21fd749cf3
diff --git a/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1 b/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1 index dede8dc..40e771c 100644 --- a/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1 +++ b/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1
@@ -1 +1 @@ -9afe32eb4676d4bcceae81605a3be6aa0e5be3d5 \ No newline at end of file +a02e2f95aa6f741f2be0ae03a4829e21fd749cf3 \ No newline at end of file
diff --git a/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt b/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt index 76959bc..06abccf 100644 --- a/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt +++ b/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt
@@ -7,3 +7,4 @@ ^^^ 32-bit vvv 64-bit v1.4 3e0cc24655847c7b922149754324a189e7092310 +v1.5 5d6d55728c7c728cef5416f37b0b71615719474e
diff --git a/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1 b/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1 index cd53027dc..33fec988 100644 --- a/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1 +++ b/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1
@@ -1 +1 @@ -3e0cc24655847c7b922149754324a189e7092310 \ No newline at end of file +5d6d55728c7c728cef5416f37b0b71615719474e \ No newline at end of file
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py index a9219e35..b8304d1 100644 --- a/tools/chrome_proxy/webdriver/lite_page.py +++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -70,18 +70,23 @@ lite_page_responses = lite_page_responses + 1 self.assertEqual(1, lite_page_responses) - # Scroll to the bottom of the window and make sure there were more - # requests that were proxied. - scroll_js = 'window.scrollTo(0,Math.max(document.body.scrollHeight));' - test_driver.ExecuteJavascriptStatement(scroll_js) - # Give some time for loading after each scroll. + # Scroll to the bottom of the window and ensure scrollHeight increases. + original_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + test_driver.ExecuteJavascriptStatement( + 'window.scrollTo(0,Math.max(document.body.scrollHeight));') + # Give some time for loading after scrolling. time.sleep(2) - test_driver.ExecuteJavascriptStatement(scroll_js) - time.sleep(2) + new_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + self.assertGreater(new_scroll_height, original_scroll_height) + + # Make sure there were more requests that were proxied. responses = test_driver.GetHTTPResponses(override_has_logs=True) self.assertNotEqual(0, len(responses)) for response in responses: self.assertHasChromeProxyViaHeader(response) + self.assertIn(response.status, [200, 204]) # Checks that Lo-Fi images are used when the user is in the # DataCompressionProxyLitePageFallback field trial and a Lite Page is not
diff --git a/tools/licenses.py b/tools/licenses.py index b47ea4e..8d0310aa 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -602,11 +602,8 @@ 'license_file': metadata['License File'], } entries.append(entry) - # Sort by size in order to improve gzip compression ratio (puts similar - # licenses near each other). The licenses are re-sorted by the JavaScript - # when loaded. - entries.sort(key=lambda entry: len(entry['content'])) + entries.sort(key=lambda entry: (entry['name'], entry['content'])) entries_contents = '\n'.join([entry['content'] for entry in entries]) file_template = open(file_template_file).read() template_contents = "<!-- Generated by licenses.py; do not edit. -->"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index bfb4c9f..9ef42b7 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -10489,20 +10489,8 @@ <owner>megjablon@chromium.org</owner> <summary> Samples of user interactions with the Data Reduction Proxy promos, First Run - Experience, and settings menu. All samples are mutually exclusive. These - samples include: - - The user interactions with the second run promo. On Android, there are three - actions that dismiss this promo (enable, dismiss, and learn more) and on iOS - there is a toggle to enable the proxy. This is sampled when the promo leaves - view. If the user clicks the link to the settings menu, the state of the - ON/OFF switch in the menu is sampled when the view is exited. - - Any other user interaction with the the ON/OFF switch in the settings menu - for reducing data usage. Only the setting changes between entering the - reducing data usage setting menu and leaving the menu will be sampled - regardless of how many times they toggle the ON/OFF switch. Other samples - that report ON/OFF settings menu changes are not also reported here. + Experience, main menu footer, and settings menu. All samples are mutually + exclusive. These samples include: The user interactions with the First Run Experience. On Android when the user sees the FRE card, the Data Reduction Proxy defaults to ON. The user @@ -10510,13 +10498,32 @@ sampled when the First Run Experience is completed and only reported if the Data Reduction Proxy card was shown. + The user interactions with the second run promo. On Android, there are two + actions that dismiss this promo (enable or dismiss). This is sampled when + the promo leaves view. + The user interactions with the Infobar promo. On Android, there are two actions that dismiss the promo (enable, dismiss). This is sampled when the promo leaves view. The user interactions with the Snackbar promo. The user can either ignore - the promo or click the action to the Settings menu. From the settings menu, + the promo or click the action to the settings menu. From the settings menu, the user may enable or disable the proxy. + + The user interactions with the main menu footer. The user can click the + footer to enter the settings menu. From the settings menu, the user may + enable or disable the proxy. + + Any other user interaction with the ON/OFF switch in the settings menu for + reducing data usage. Only the setting changes between entering the reducing + data usage setting menu and leaving the menu will be sampled regardless of + how many times they toggle the ON/OFF switch. Other samples that report + ON/OFF settings menu changes are not also reported here. + + The views of and user interactions with the site breakdown in the settings + menu. The site breakdown can be sorted by data saved descending or data used + descending, and expanded to view more sites. The Data Reduction statistics + can also be reset. </summary> </histogram> @@ -74345,7 +74352,21 @@ </summary> </histogram> -<histogram name="TaskScheduler.TaskLatency" units="ms"> +<histogram base="true" name="TaskScheduler.TaskLatency" units="ms"> + <obsolete> + Deprecated 4/2017. Units changed from milliseconds to microseconds. + </obsolete> + <owner>fdoray@chromium.org</owner> + <owner>gab@chromium.org</owner> + <owner>robliao@chromium.org</owner> + <summary> + Time elapsed between when a task is posted and when it starts to run. + Recorded for each task that runs inside the TaskScheduler. + </summary> +</histogram> + +<histogram base="true" name="TaskScheduler.TaskLatencyMicroseconds" + units="microseconds"> <owner>fdoray@chromium.org</owner> <owner>gab@chromium.org</owner> <owner>robliao@chromium.org</owner> @@ -89350,18 +89371,24 @@ label="Snackbar promo link clicked, and the proxy was disabled"/> <int value="15" label="Snackbar promo dismissed (no action taken)"/> <int value="16" - label="Arrived at settings menu by main menu item: entered off, exited - off"/> + label="Arrived at settings menu by main menu footer: entered off, + exited off"/> <int value="17" - label="Arrived at settings menu by main menu item: entered off, exited - on"/> + label="Arrived at settings menu by main menu footer: entered off, + exited on"/> <int value="18" - label="Arrived at settings menu by main menu item: entered on, exited + label="Arrived at settings menu by main menu footer: entered on, exited off"/> <int value="19" - label="Arrived at settings menu by main menu item: entered on, exited + label="Arrived at settings menu by main menu footer: entered on, exited on"/> <int value="20" label="Data usage stats reset via the settings menu"/> + <int value="21" label="Main menu footer displayed on"/> + <int value="22" label="Main menu footer displayed off"/> + <int value="23" label="Site breakdown displayed on the settings menu"/> + <int value="24" label="Site breakdown sorted by data saved"/> + <int value="25" label="Site breakdown sorted by data used"/> + <int value="26" label="Site breakdown expanded to see more sites"/> </enum> <enum name="DataUrlMimeType" type="int"> @@ -92734,6 +92761,8 @@ <int value="365" label="DeviceLoginScreenInputMethods"/> <int value="366" label="EnableCommonNameFallbackForLocalAnchors"/> <int value="367" label="InstantTetheringAllowed"/> + <int value="368" label="RemoteAccessHostDomainList"/> + <int value="369" label="RemoteAccessHostClientDomainList"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -103922,6 +103951,7 @@ <int value="646252875" label="ReadItLaterInMenu:enabled"/> <int value="646738320" label="disable-gesture-editing"/> <int value="650602639" label="enable-autofill-keyboard-accessory-view"/> + <int value="651421878" label="VideoRotateToFullscreen:enabled"/> <int value="652561231" label="CustomContextMenu:enabled"/> <int value="683410401" label="enable-proximity-auth-bluetooth-low-energy-discovery"/> @@ -104066,6 +104096,7 @@ <int value="1209221384" label="enable-experimental-accessibility-features"/> <int value="1210343926" label="enable-drop-sync-credential"/> <int value="1211284676" label="V8NoTurbo:enabled"/> + <int value="1214455758" label="VideoRotateToFullscreen:disabled"/> <int value="1219628795" label="PrintScaling:disabled"/> <int value="1219826373" label="ServiceWorkerNavigationPreload:enabled"/> <int value="1220171692" label="SpeculativeLaunchServiceWorker:enabled"/> @@ -104534,6 +104565,7 @@ <int value="20" label="Has border radius"/> <int value="21" label="Has clip related property"/> <int value="22" label="Has box shadow from non-root layer"/> + <int value="23" label="Is not stacking context"/> </enum> <enum name="MakeChromeDefaultResult" type="int"> @@ -127549,6 +127581,12 @@ <affected-histogram name="TaskScheduler.TaskLatency.UserBlockingTaskPriority"/> <affected-histogram name="TaskScheduler.TaskLatency.UserVisibleTaskPriority"/> + <affected-histogram + name="TaskScheduler.TaskLatencyMicroseconds.BackgroundTaskPriority"/> + <affected-histogram + name="TaskScheduler.TaskLatencyMicroseconds.UserBlockingTaskPriority"/> + <affected-histogram + name="TaskScheduler.TaskLatencyMicroseconds.UserVisibleTaskPriority"/> </histogram_suffixes> <histogram_suffixes name="TaskSchedulerTaskPriority" separator="."> @@ -127579,6 +127617,7 @@ Deprecated 12/2016. Pool name removed from task latency histogram name. </obsolete> </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds"/> </histogram_suffixes> <histogram_suffixes name="TaskSchedulerWorkerPool" separator=".">
diff --git a/tools/perf/page_sets/system_health/searching_stories.py b/tools/perf/page_sets/system_health/searching_stories.py index 2e2c8f41..bdbc046 100644 --- a/tools/perf/page_sets/system_health/searching_stories.py +++ b/tools/perf/page_sets/system_health/searching_stories.py
@@ -70,6 +70,7 @@ action_runner.ScrollPage(use_touch=True, distance=500) +@decorators.Disabled('android-webview') # Webview does not have new tab page. class MobileNewTabPageStory(system_health_story.SystemHealthStory): """Story that loads new tab page and performs searches.
diff --git a/ui/aura/mus/window_manager_delegate.h b/ui/aura/mus/window_manager_delegate.h index 917fe539..9918870 100644 --- a/ui/aura/mus/window_manager_delegate.h +++ b/ui/aura/mus/window_manager_delegate.h
@@ -65,7 +65,9 @@ // this does nothing. virtual void RequestClose(Window* window) = 0; - // Blocks until the initial displays have been received. + // Blocks until the initial displays have been received, or if displays are + // not automatically created until the connection to mus has been + // established. virtual bool WaitForInitialDisplays() = 0; // Used by the window manager to create a new display. This is only useful if
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc index 52b15cb..b69109eb 100644 --- a/ui/aura/mus/window_tree_client.cc +++ b/ui/aura/mus/window_tree_client.cc
@@ -1488,6 +1488,7 @@ void WindowTreeClient::OnConnect(ClientSpecificId client_id) { client_id_ = client_id; + got_initial_displays_ = true; if (window_manager_delegate_) window_manager_delegate_->OnWmConnected(); }
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h index 73e641fa..edd5d6df 100644 --- a/ui/aura/window_tree_host.h +++ b/ui/aura/window_tree_host.h
@@ -133,6 +133,7 @@ // Gets the InputMethod instance, if NULL, creates & owns it. ui::InputMethod* GetInputMethod(); + bool has_input_method() const { return input_method_ != nullptr; } // Sets a shared unowned InputMethod. This is used when there is a singleton // InputMethod shared between multiple WindowTreeHost instances.
diff --git a/ui/base/cocoa/touch_bar_forward_declarations.h b/ui/base/cocoa/touch_bar_forward_declarations.h index 34390b7..fce7d997 100644 --- a/ui/base/cocoa/touch_bar_forward_declarations.h +++ b/ui/base/cocoa/touch_bar_forward_declarations.h
@@ -118,6 +118,16 @@ #endif // MAC_OS_X_VERSION_10_12_1 } // extern "C" +#if !defined(MAC_OS_X_VERSION_10_12_2) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_2 + +@interface NSTouchBar (SierraPointTwoSDK) +@property(copy, nullable) + NSTouchBarItemIdentifier escapeKeyReplacementItemIdentifier; +@end + +#endif // MAC_OS_X_VERSION_10_12_2 + #pragma clang assume_nonnull end #endif // UI_BASE_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
diff --git a/ui/base/ime/BUILD.gn b/ui/base/ime/BUILD.gn index ba62c64..0eb784c 100644 --- a/ui/base/ime/BUILD.gn +++ b/ui/base/ime/BUILD.gn
@@ -42,6 +42,8 @@ "chromeos/input_method_descriptor.h", "chromeos/input_method_manager.cc", "chromeos/input_method_manager.h", + "chromeos/mock_component_extension_ime_manager.cc", + "chromeos/mock_component_extension_ime_manager.h", "chromeos/mock_component_extension_ime_manager_delegate.cc", "chromeos/mock_component_extension_ime_manager_delegate.h", "chromeos/mock_ime_candidate_window_handler.cc",
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.h b/ui/base/ime/chromeos/component_extension_ime_manager.h index 9f273043..62240dd 100644 --- a/ui/base/ime/chromeos/component_extension_ime_manager.h +++ b/ui/base/ime/chromeos/component_extension_ime_manager.h
@@ -104,7 +104,8 @@ input_method::InputMethodDescriptors GetAllIMEAsInputMethodDescriptor(); // Returns all XKB keyboard IME as InputMethodDescriptors. - input_method::InputMethodDescriptors GetXkbIMEAsInputMethodDescriptor(); + virtual input_method::InputMethodDescriptors + GetXkbIMEAsInputMethodDescriptor(); private: // Finds ComponentExtensionIME and EngineDescription associated with
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager.cc b/ui/base/ime/chromeos/mock_component_extension_ime_manager.cc new file mode 100644 index 0000000..8ba58ea6 --- /dev/null +++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager.cc
@@ -0,0 +1,14 @@ +// 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 "ui/base/ime/chromeos/mock_component_extension_ime_manager.h" + +namespace chromeos { + +input_method::InputMethodDescriptors +MockComponentExtensionIMEManager::GetXkbIMEAsInputMethodDescriptor() { + return input_method::InputMethodDescriptors(); +} + +} // namespace chromeos
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager.h b/ui/base/ime/chromeos/mock_component_extension_ime_manager.h new file mode 100644 index 0000000..829f562 --- /dev/null +++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager.h
@@ -0,0 +1,21 @@ +// 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 UI_BASE_IME_MOCK_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_H_ +#define UI_BASE_IME_MOCK_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_H_ + +#include "ui/base/ime/chromeos/component_extension_ime_manager.h" + +namespace chromeos { + +class UI_BASE_IME_EXPORT MockComponentExtensionIMEManager + : public ComponentExtensionIMEManager { + public: + input_method::InputMethodDescriptors GetXkbIMEAsInputMethodDescriptor() + override; +}; + +} // namespace chromeos + +#endif // UI_BASE_IME_MOCK_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_H_
diff --git a/ui/gfx/linux/OWNERS b/ui/gfx/linux/OWNERS new file mode 100644 index 0000000..4bd7b3f51 --- /dev/null +++ b/ui/gfx/linux/OWNERS
@@ -0,0 +1,4 @@ +dcastagna@chromium.org +dongseong.hwang@chromium.org +dnicoara@chromium.org +reveman@chromium.org
diff --git a/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/ui/gfx/linux/client_native_pixmap_dmabuf.cc index 31ff4f43..4927daf 100644 --- a/ui/gfx/linux/client_native_pixmap_dmabuf.cc +++ b/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -19,7 +19,7 @@ #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) #include <linux/dma-buf.h> #else #include <linux/types.h>
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc index 789f1b5e..9ffa42c8 100644 --- a/ui/views/animation/ink_drop_host_view.cc +++ b/ui/views/animation/ink_drop_host_view.cc
@@ -132,9 +132,7 @@ SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); - ink_drop_mask_ = CreateInkDropMask(); - if (ink_drop_mask_) - ink_drop_layer->SetMaskLayer(ink_drop_mask_->layer()); + InstallInkDropMask(ink_drop_layer); layer()->Add(ink_drop_layer); layer()->StackAtBottom(ink_drop_layer); } @@ -280,6 +278,19 @@ return ink_drop_.get(); } +void InkDropHostView::InstallInkDropMask(ui::Layer* ink_drop_layer) { +// Layer masks don't work on Windows. See crbug.com/713359 +#if !defined(OS_WIN) + ink_drop_mask_ = CreateInkDropMask(); + if (ink_drop_mask_) + ink_drop_layer->SetMaskLayer(ink_drop_mask_->layer()); +#endif +} + +void InkDropHostView::ResetInkDropMask() { + ink_drop_mask_.reset(); +} + std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() { std::unique_ptr<InkDropImpl> ink_drop = base::MakeUnique<InkDropImpl>(this, size());
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h index 15199209..9aad738 100644 --- a/ui/views/animation/ink_drop_host_view.h +++ b/ui/views/animation/ink_drop_host_view.h
@@ -114,6 +114,12 @@ // subclasses should be able to call SetInkDropMode() during construction. InkDrop* GetInkDrop(); + // Initializes and sets a mask on |ink_drop_layer|. No-op if + // CreateInkDropMask() returns null. + void InstallInkDropMask(ui::Layer* ink_drop_layer); + + void ResetInkDropMask(); + // Returns an InkDropImpl configured to work well with a // flood-fill ink drop ripple. std::unique_ptr<InkDropImpl> CreateDefaultFloodFillInkDropImpl();
diff --git a/ui/views/animation/ink_drop_mask.cc b/ui/views/animation/ink_drop_mask.cc index de839a9..d95286d9 100644 --- a/ui/views/animation/ink_drop_mask.cc +++ b/ui/views/animation/ink_drop_mask.cc
@@ -35,7 +35,7 @@ // RoundRectInkDropMask RoundRectInkDropMask::RoundRectInkDropMask(const gfx::Size& layer_size, - const gfx::Insets& mask_insets, + const gfx::InsetsF& mask_insets, int corner_radius) : InkDropMask(layer_size), mask_insets_(mask_insets), @@ -48,7 +48,7 @@ flags.setAntiAlias(true); ui::PaintRecorder recorder(context, layer()->size()); - gfx::Rect bounds = layer()->bounds(); + gfx::RectF bounds(layer()->bounds()); bounds.Inset(mask_insets_); recorder.canvas()->DrawRoundRect(bounds, corner_radius_, flags); }
diff --git a/ui/views/animation/ink_drop_mask.h b/ui/views/animation/ink_drop_mask.h index 347e54f..bb78f4e 100644 --- a/ui/views/animation/ink_drop_mask.h +++ b/ui/views/animation/ink_drop_mask.h
@@ -8,7 +8,7 @@ #include "base/macros.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_delegate.h" -#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/insets_f.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/views_export.h" @@ -47,14 +47,14 @@ class VIEWS_EXPORT RoundRectInkDropMask : public InkDropMask { public: RoundRectInkDropMask(const gfx::Size& layer_size, - const gfx::Insets& mask_insets, + const gfx::InsetsF& mask_insets, int corner_radius); private: // Overriden from InkDropMask: void OnPaintLayer(const ui::PaintContext& context) override; - gfx::Insets mask_insets_; + gfx::InsetsF mask_insets_; int corner_radius_; DISALLOW_COPY_AND_ASSIGN(RoundRectInkDropMask);
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc index d114946..d74fc8d 100644 --- a/ui/views/controls/button/label_button.cc +++ b/ui/views/controls/button/label_button.cc
@@ -423,10 +423,12 @@ image()->SetPaintToLayer(); image()->layer()->SetFillsBoundsOpaquely(false); ink_drop_container_->AddInkDropLayer(ink_drop_layer); + InstallInkDropMask(ink_drop_layer); } void LabelButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { image()->DestroyLayer(); + ResetInkDropMask(); ink_drop_container_->RemoveInkDropLayer(ink_drop_layer); }