diff --git a/DEPS b/DEPS index 211f07b..7c142294 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': 'eccf352a2843bd5c732abfd6cc8a8449cde97a26', + 'skia_revision': 'e79b473714866682dea85b66c005c5bb2ff6a397', # 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': 'b860a49fb15b1e6f70e69aef93a591cbcd7793f0', + 'v8_revision': '17189bf456b4b671a3c404724d4b1599678c77a4', # 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. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'e0b592236db902e3e8cbca7ec64f8e2b192e1935', + 'pdfium_revision': 'aeee187c927c07f47a9e5886a417dcc58badefb6', # 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.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index a67d721..bc78d24 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -428,6 +428,8 @@ "system/palette/tools/laser_pointer_mode.h", "system/palette/tools/magnifier_mode.cc", "system/palette/tools/magnifier_mode.h", + "system/palette/tools/metalayer_mode.cc", + "system/palette/tools/metalayer_mode.h", "system/power/battery_notification.cc", "system/power/battery_notification.h", "system/power/dual_role_notification.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 7ade540..3b3d467 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -394,6 +394,9 @@ <message name="IDS_ASH_STYLUS_TOOLS_MAGNIFIER_MODE" desc="Title of the magnification mode in the stylus tools. Clicking this button opens up a magnifier. The magnifier remains active until the user turns it off by tapping the same button again."> Magnifying glass mode </message> + <message name="IDS_ASH_STYLUS_TOOLS_METALAYER_MODE" desc="Title of the metalayer mode in the stylus tools. Clicking this button opens up the voice interaction overlay. The overlay remains active until the user completes the interaction."> + Metalayer mode + </message> <message name="IDS_ASH_STYLUS_TOOLS_TITLE" desc="The title of the stylus tools dialog in the ash shelf."> Stylus tools </message>
diff --git a/ash/palette_delegate.h b/ash/palette_delegate.h index 942f09e..8f370d6b 100644 --- a/ash/palette_delegate.h +++ b/ash/palette_delegate.h
@@ -54,6 +54,17 @@ // Cancels any active partial screenshot session. virtual void CancelPartialScreenshot() = 0; + // Returns true if the metalayer is available. + virtual bool IsMetalayerSupported() = 0; + + // Shows the metalayer. + // |closed| will be invoked when the metalayer is closed or + // if the metalayer could not be shown. + virtual void ShowMetalayer(const base::Closure& closed) = 0; + + // Hides the metalayer. + virtual void HideMetalayer() = 0; + private: DISALLOW_ASSIGN(PaletteDelegate); };
diff --git a/ash/public/interfaces/session_controller.mojom b/ash/public/interfaces/session_controller.mojom index ed066cbd..0dd24b16 100644 --- a/ash/public/interfaces/session_controller.mojom +++ b/ash/public/interfaces/session_controller.mojom
@@ -143,6 +143,14 @@ // active user session. SetUserSessionOrder(array<uint32> user_session_ids); + // Runs the pre-lock animation to start locking ash. When the call returns, + // |locked| == true means that the post-lock animation is finished and ash is + // fully locked. Otherwise |locked| is false, which means something is wrong + // for the lock and ash is not locked. When the call returns with a true + // |locked|, screen locker runs the post lock jobs such as a11y announcement + // etc. Invoked by the screen locker during initialization. + StartLock() => (bool locked); + // Runs the pre-unlock animation. Invoked by the screen locker before // dismissing. When the mojo call returns, screen locker takes that as a // signal of finished unlock animation and dismisses itself.
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc index 873f5776..94ee2bfb 100644 --- a/ash/session/session_controller.cc +++ b/ash/session/session_controller.cc
@@ -42,9 +42,14 @@ } // namespace -SessionController::SessionController() : state_(GetDefaultSessionState()) {} +SessionController::SessionController() + : state_(GetDefaultSessionState()), weak_ptr_factory_(this) {} -SessionController::~SessionController() {} +SessionController::~SessionController() { + // Abort pending start lock request. + if (!start_lock_callback_.is_null()) + std::move(start_lock_callback_).Run(false /* locked */); +} void SessionController::BindRequest(mojom::SessionControllerRequest request) { bindings_.AddBinding(this, std::move(request)); @@ -228,6 +233,19 @@ } } +void SessionController::StartLock(const StartLockCallback& callback) { + DCHECK(start_lock_callback_.is_null()); + start_lock_callback_ = callback; + + LockStateController* const lock_state_controller = + Shell::Get()->lock_state_controller(); + + lock_state_controller->SetLockScreenDisplayedCallback( + base::Bind(&SessionController::OnLockAnimationFinished, + weak_ptr_factory_.GetWeakPtr())); + lock_state_controller->OnStartingLock(); +} + void SessionController::RunUnlockAnimation( const RunUnlockAnimationCallback& callback) { is_unlocking_ = true; @@ -353,4 +371,9 @@ observer.OnLoginStatusChanged(login_status_); } +void SessionController::OnLockAnimationFinished() { + if (!start_lock_callback_.is_null()) + std::move(start_lock_callback_).Run(true /* locked */); +} + } // namespace ash
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h index fa594e1..6bab9fe 100644 --- a/ash/session/session_controller.h +++ b/ash/session/session_controller.h
@@ -13,7 +13,9 @@ #include "ash/login_status.h" #include "ash/public/cpp/session_types.h" #include "ash/public/interfaces/session_controller.mojom.h" +#include "base/callback.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -117,6 +119,7 @@ void UpdateUserSession(mojom::UserSessionPtr user_session) override; void SetUserSessionOrder( const std::vector<uint32_t>& user_session_order) override; + void StartLock(const StartLockCallback& callback) override; void RunUnlockAnimation(const RunUnlockAnimationCallback& callback) override; void NotifyChromeTerminating() override; @@ -138,6 +141,11 @@ // Update the |login_status_| and notify observers. void UpdateLoginStatus(); + // Used as lock screen displayed callback of LockStateController and invoked + // when post lock animation finishes and ash is fully locked. It would then + // run |start_lock_callback_| to indicate ash is locked successfully. + void OnLockAnimationFinished(); + // Bindings for mojom::SessionController interface. mojo::BindingSet<mojom::SessionController> bindings_; @@ -167,8 +175,13 @@ // animation starts and reset when session state is no longer LOCKED. bool is_unlocking_ = false; + // Pending callback for the StartLock request. + base::OnceCallback<void(bool)> start_lock_callback_; + base::ObserverList<ash::SessionObserver> observers_; + base::WeakPtrFactory<SessionController> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(SessionController); };
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 8aab1ae..6474dd5f 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -51,6 +51,9 @@ done.Run(); } void CancelPartialScreenshot() override {} + bool IsMetalayerSupported() override { return false; } + void ShowMetalayer(const base::Closure& closed) override {} + void HideMetalayer() override {} private: DISALLOW_COPY_AND_ASSIGN(PaletteDelegateImpl);
diff --git a/ash/system/palette/palette_ids.cc b/ash/system/palette/palette_ids.cc index 1e2338f4..63614e8 100644 --- a/ash/system/palette/palette_ids.cc +++ b/ash/system/palette/palette_ids.cc
@@ -21,6 +21,8 @@ return "LASER_POINTER"; case PaletteToolId::MAGNIFY: return "MAGNIFY"; + case PaletteToolId::METALAYER: + return "METALAYER"; } NOTREACHED(); @@ -53,6 +55,8 @@ return PALETTE_LASER_POINTER; case PaletteToolId::MAGNIFY: return PALETTE_MAGNIFY; + case PaletteToolId::METALAYER: + return PALETTE_METALAYER; } NOTREACHED();
diff --git a/ash/system/palette/palette_ids.h b/ash/system/palette/palette_ids.h index d3369a26..5bfd47f 100644 --- a/ash/system/palette/palette_ids.h +++ b/ash/system/palette/palette_ids.h
@@ -25,6 +25,7 @@ CAPTURE_SCREEN, LASER_POINTER, MAGNIFY, + METALAYER, }; // Usage of each pen palette option. This enum is used to back an UMA histogram @@ -38,6 +39,7 @@ PALETTE_NEW_NOTE, PALETTE_MAGNIFY, PALETTE_LASER_POINTER, + PALETTE_METALAYER, PALETTE_OPTIONS_COUNT };
diff --git a/ash/system/palette/palette_tool.cc b/ash/system/palette/palette_tool.cc index 74b88a0..44957a1 100644 --- a/ash/system/palette/palette_tool.cc +++ b/ash/system/palette/palette_tool.cc
@@ -11,6 +11,7 @@ #include "ash/system/palette/tools/create_note_action.h" #include "ash/system/palette/tools/laser_pointer_mode.h" #include "ash/system/palette/tools/magnifier_mode.h" +#include "ash/system/palette/tools/metalayer_mode.h" #include "base/memory/ptr_util.h" #include "ui/gfx/paint_vector_icon.h" @@ -21,6 +22,7 @@ tool_manager->AddTool(base::MakeUnique<CaptureRegionMode>(tool_manager)); tool_manager->AddTool(base::MakeUnique<CaptureScreenAction>(tool_manager)); tool_manager->AddTool(base::MakeUnique<CreateNoteAction>(tool_manager)); + tool_manager->AddTool(base::MakeUnique<MetalayerMode>(tool_manager)); tool_manager->AddTool(base::MakeUnique<LaserPointerMode>(tool_manager)); tool_manager->AddTool(base::MakeUnique<MagnifierMode>(tool_manager)); }
diff --git a/ash/system/palette/tools/metalayer_mode.cc b/ash/system/palette/tools/metalayer_mode.cc new file mode 100644 index 0000000..ff3a8a7 --- /dev/null +++ b/ash/system/palette/tools/metalayer_mode.cc
@@ -0,0 +1,65 @@ +// 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/system/palette/tools/metalayer_mode.h" + +#include "ash/palette_delegate.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/system/palette/palette_ids.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +MetalayerMode::MetalayerMode(Delegate* delegate) + : CommonPaletteTool(delegate), weak_factory_(this) {} + +MetalayerMode::~MetalayerMode() {} + +PaletteGroup MetalayerMode::GetGroup() const { + return PaletteGroup::MODE; +} + +PaletteToolId MetalayerMode::GetToolId() const { + return PaletteToolId::METALAYER; +} + +void MetalayerMode::OnEnable() { + CommonPaletteTool::OnEnable(); + + Shell::Get()->palette_delegate()->ShowMetalayer( + base::Bind(&MetalayerMode::OnMetalayerDone, weak_factory_.GetWeakPtr())); + delegate()->HidePalette(); +} + +void MetalayerMode::OnDisable() { + CommonPaletteTool::OnDisable(); + + Shell::Get()->palette_delegate()->HideMetalayer(); +} + +const gfx::VectorIcon& MetalayerMode::GetActiveTrayIcon() const { + // TODO(kaznacheev) replace with the correct icon when it is available + return kPaletteTrayIconCaptureRegionIcon; +} + +const gfx::VectorIcon& MetalayerMode::GetPaletteIcon() const { + // TODO(kaznacheev) replace with the correct icon when it is available + return kPaletteActionCaptureRegionIcon; +} + +views::View* MetalayerMode::CreateView() { + if (!Shell::Get()->palette_delegate()->IsMetalayerSupported()) + return nullptr; + + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_METALAYER_MODE)); +} + +void MetalayerMode::OnMetalayerDone() { + delegate()->DisableTool(GetToolId()); +} + +} // namespace ash
diff --git a/ash/system/palette/tools/metalayer_mode.h b/ash/system/palette/tools/metalayer_mode.h new file mode 100644 index 0000000..c839fa9 --- /dev/null +++ b/ash/system/palette/tools/metalayer_mode.h
@@ -0,0 +1,42 @@ +// 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_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_ +#define ASH_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_ + +#include "ash/ash_export.h" +#include "ash/system/palette/common_palette_tool.h" +#include "base/memory/weak_ptr.h" + +namespace ash { + +// A palette tool that lets the user select a screen region to be passed +// to the voice interaction framework. +class ASH_EXPORT MetalayerMode : public CommonPaletteTool { + public: + explicit MetalayerMode(Delegate* delegate); + ~MetalayerMode() override; + + private: + // PaletteTool: + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + void OnEnable() override; + void OnDisable() override; + const gfx::VectorIcon& GetActiveTrayIcon() const override; + views::View* CreateView() override; + + // CommonPaletteTool: + const gfx::VectorIcon& GetPaletteIcon() const override; + + void OnMetalayerDone(); + + base::WeakPtrFactory<MetalayerMode> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(MetalayerMode); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_
diff --git a/ash/test/test_palette_delegate.cc b/ash/test/test_palette_delegate.cc index 49881d3..5110f266 100644 --- a/ash/test/test_palette_delegate.cc +++ b/ash/test/test_palette_delegate.cc
@@ -44,4 +44,12 @@ void TestPaletteDelegate::CancelPartialScreenshot() {} +bool TestPaletteDelegate::IsMetalayerSupported() { + return false; +} + +void TestPaletteDelegate::ShowMetalayer(const base::Closure& closed) {} + +void TestPaletteDelegate::HideMetalayer() {} + } // namespace ash
diff --git a/ash/test/test_palette_delegate.h b/ash/test/test_palette_delegate.h index a572eb3..4fee8b0 100644 --- a/ash/test/test_palette_delegate.h +++ b/ash/test/test_palette_delegate.h
@@ -51,6 +51,9 @@ void TakeScreenshot() override; void TakePartialScreenshot(const base::Closure& done) override; void CancelPartialScreenshot() override; + bool IsMetalayerSupported() override; + void ShowMetalayer(const base::Closure& closed) override; + void HideMetalayer() override; int create_note_count_ = 0; int has_note_app_count_ = 0;
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc index 2370054f..0b996a1 100644 --- a/ash/wm/lock_state_controller.cc +++ b/ash/wm/lock_state_controller.cc
@@ -181,8 +181,9 @@ } void LockStateController::SetLockScreenDisplayedCallback( - const base::Closure& callback) { - lock_screen_displayed_callback_ = callback; + base::OnceClosure callback) { + DCHECK(lock_screen_displayed_callback_.is_null()); + lock_screen_displayed_callback_ = std::move(callback); } void LockStateController::OnHostCloseRequested( @@ -496,10 +497,9 @@ VLOG(1) << "PostLockAnimationFinished"; ShellPort::Get()->OnLockStateEvent( LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED); - if (!lock_screen_displayed_callback_.is_null()) { - lock_screen_displayed_callback_.Run(); - lock_screen_displayed_callback_.Reset(); - } + if (!lock_screen_displayed_callback_.is_null()) + std::move(lock_screen_displayed_callback_).Run(); + CHECK(!views::MenuController::GetActiveInstance()); if (shutdown_after_lock_) { shutdown_after_lock_ = false;
diff --git a/ash/wm/lock_state_controller.h b/ash/wm/lock_state_controller.h index bbda1be..aa4530c3 100644 --- a/ash/wm/lock_state_controller.h +++ b/ash/wm/lock_state_controller.h
@@ -116,7 +116,7 @@ // Sets up the callback that should be called once lock animation is finished. // Callback is guaranteed to be called once and then discarded. - void SetLockScreenDisplayedCallback(const base::Closure& callback); + void SetLockScreenDisplayedCallback(base::OnceClosure callback); // aura::WindowTreeHostObserver override: void OnHostCloseRequested(const aura::WindowTreeHost* host) override; @@ -240,7 +240,7 @@ // etc. are shut down. base::OneShotTimer real_shutdown_timer_; - base::Closure lock_screen_displayed_callback_; + base::OnceClosure lock_screen_displayed_callback_; ScopedSessionObserver scoped_session_observer_;
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h index 86fac9c..2c3d506 100644 --- a/base/mac/sdk_forward_declarations.h +++ b/base/mac/sdk_forward_declarations.h
@@ -187,6 +187,7 @@ @interface NSObject (ElCapitanSDK) - (NSLayoutConstraint*)constraintEqualToConstant:(CGFloat)c; +- (NSLayoutConstraint*)constraintGreaterThanOrEqualToConstant:(CGFloat)c; @end @interface NSView (ElCapitanSDK) @@ -246,6 +247,10 @@ action:(SEL)action; @end +@interface NSApplication (SierraPointOneSDK) +@property BOOL automaticCustomizeTouchBarMenuItemEnabled; +@end + #endif // MAC_OS_X_VERSION_10_12_1 // ----------------------------------------------------------------------------
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 3b77c055..6a495cc 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -20,6 +20,9 @@ if (is_mac) { import("//build/config/mac/symbols.gni") } +if (is_ios) { + import("//build/config/ios/ios_sdk.gni") +} declare_args() { # Default to warnings as errors for default workflow, where we catch @@ -1102,6 +1105,17 @@ # TODO(thakis ): https://crbug.com/683349 "-Wno-user-defined-warnings", ] + } else if (use_xcode_clang && + (xcode_version == "0830" || xcode_version == "0831" || + xcode_version == "0832")) { + # This is necessary to allow a progressive transition from using xcode 8 to 8.3. Remove when all bots are migrated to 8.3. + cflags += [ + # TODO(thakis): https://crbug.com/604888 + "-Wno-undefined-var-template", + + # TODO(hans): https://crbug.com/637306 + "-Wno-address-of-packed-member", + ] } } }
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc index 0ee4e83..4c354a7 100644 --- a/cc/layers/surface_layer_unittest.cc +++ b/cc/layers/surface_layer_unittest.cc
@@ -32,6 +32,9 @@ namespace cc { namespace { +using testing::_; +using testing::Eq; + static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1); class SurfaceLayerTest : public testing::Test { @@ -63,33 +66,20 @@ FakeLayerTreeHostImpl host_impl_; }; -class TestSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory { - protected: - void SatisfySequence(const SurfaceSequence& seq) const override { - *out_seq_ = seq; - } - - void RequireSequence(const SurfaceId& id, - const SurfaceSequence& seq) const override { - *out_id_ = id; - out_set_->insert(seq); - } - +class MockSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory { public: - TestSurfaceReferenceFactory(SurfaceSequence* out_seq, - SurfaceId* out_id, - std::set<SurfaceSequence>* out_set) - : out_seq_(out_seq), out_id_(out_id), out_set_(out_set) {} + MockSurfaceReferenceFactory() {} + + // SequenceSurfaceReferenceFactory implementation. + MOCK_CONST_METHOD1(SatisfySequence, void(const SurfaceSequence&)); + MOCK_CONST_METHOD2(RequireSequence, + void(const SurfaceId&, const SurfaceSequence&)); protected: - ~TestSurfaceReferenceFactory() override = default; + ~MockSurfaceReferenceFactory() override = default; private: - SurfaceSequence* out_seq_; - SurfaceId* out_id_; - std::set<SurfaceSequence>* out_set_; - - DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory); + DISALLOW_COPY_AND_ASSIGN(MockSurfaceReferenceFactory); }; // Check that one surface can be referenced by multiple LayerTreeHosts, and @@ -97,17 +87,26 @@ TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) { const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create(); - SurfaceSequence blank_change; // Receives sequence if commit doesn't happen. - - SurfaceId required_id; - std::set<SurfaceSequence> required_seq; - scoped_refptr<SurfaceReferenceFactory> ref_factory = - new TestSurfaceReferenceFactory(&blank_change, &required_id, - &required_seq); - auto layer = SurfaceLayer::Create(ref_factory); - SurfaceInfo info( + const SurfaceInfo info( SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)), 1.f, gfx::Size(1, 1)); + const SurfaceSequence expected_seq1(FrameSinkId(1, 1), 1u); + const SurfaceSequence expected_seq2(FrameSinkId(2, 2), 1u); + const SurfaceId expected_id(kArbitraryFrameSinkId, + LocalSurfaceId(1, kArbitraryToken)); + + scoped_refptr<MockSurfaceReferenceFactory> ref_factory = + new testing::StrictMock<MockSurfaceReferenceFactory>(); + + // We are going to set up the SurfaceLayers and LayerTreeHosts. Each layer + // will require a sequence and no sequence should be satisfied for now. + EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq1))) + .Times(1); + EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq2))) + .Times(1); + EXPECT_CALL(*ref_factory, SatisfySequence(_)).Times(0); + + auto layer = SurfaceLayer::Create(ref_factory); layer->SetPrimarySurfaceInfo(info); layer_tree_host_->GetSurfaceSequenceGenerator()->set_frame_sink_id( FrameSinkId(1, 1)); @@ -117,57 +116,40 @@ std::unique_ptr<FakeLayerTreeHost> layer_tree_host2 = FakeLayerTreeHost::Create(&fake_client_, &task_graph_runner_, animation_host2.get()); - auto layer2 = SurfaceLayer::Create(std::move(ref_factory)); + auto layer2 = SurfaceLayer::Create(ref_factory); layer2->SetPrimarySurfaceInfo(info); layer_tree_host2->GetSurfaceSequenceGenerator()->set_frame_sink_id( FrameSinkId(2, 2)); layer_tree_host2->SetRootLayer(layer2); - // Layers haven't been removed, so no sequence should be satisfied. - EXPECT_FALSE(blank_change.is_valid()); + testing::Mock::VerifyAndClearExpectations(ref_factory.get()); - SurfaceSequence expected1(FrameSinkId(1, 1), 1u); - SurfaceSequence expected2(FrameSinkId(2, 2), 1u); - + // Destroy the second LayerTreeHost. The sequence generated by its + // SurfaceLayer must be satisfied and no new sequences must be required. + EXPECT_CALL(*ref_factory, SatisfySequence(Eq(expected_seq2))).Times(1); layer_tree_host2->SetRootLayer(nullptr); layer_tree_host2.reset(); animation_host2 = nullptr; - - // Layer was removed so sequence from second LayerTreeHost should be - // satisfied. base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(blank_change == expected2); + testing::Mock::VerifyAndClearExpectations(ref_factory.get()); - // Set of sequences that need to be satisfied should include sequences from - // both trees. - EXPECT_TRUE(required_id == SurfaceId(kArbitraryFrameSinkId, - LocalSurfaceId(1, kArbitraryToken))); - EXPECT_EQ(2u, required_seq.size()); - EXPECT_TRUE(required_seq.count(expected1)); - EXPECT_TRUE(required_seq.count(expected2)); - + // Destroy the first LayerTreeHost. The sequence generated by its + // SurfaceLayer must be satisfied and no new sequences must be required. + EXPECT_CALL(*ref_factory, SatisfySequence(expected_seq1)).Times(1); + EXPECT_CALL(*ref_factory, RequireSequence(_, _)).Times(0); layer_tree_host_->SetRootLayer(nullptr); layer_tree_host_.reset(); - - // Layer was removed so sequence from first LayerTreeHost should be - // satisfied. base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(blank_change == expected1); - - // No more SurfaceSequences should have been generated that need to have be - // satisfied. - EXPECT_EQ(2u, required_seq.size()); + testing::Mock::VerifyAndClearExpectations(ref_factory.get()); } // This test verifies that the primary and fallback SurfaceInfo are pushed // across from SurfaceLayer to SurfaceLayerImpl. TEST_F(SurfaceLayerTest, SurfaceInfoPushProperties) { - SurfaceSequence blank_change; - SurfaceId required_id; - std::set<SurfaceSequence> required_sequences; + // We use a nice mock here because we are not really interested in calls to + // MockSurfaceReferenceFactory and we don't want warnings printed. scoped_refptr<SurfaceReferenceFactory> ref_factory = - new TestSurfaceReferenceFactory(&blank_change, &required_id, - &required_sequences); + new testing::NiceMock<MockSurfaceReferenceFactory>(); scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(ref_factory); layer_tree_host_->SetRootLayer(layer); @@ -208,24 +190,34 @@ void BeginTest() override { layer_tree_host()->GetSurfaceSequenceGenerator()->set_frame_sink_id( FrameSinkId(1, 1)); - layer_ = SurfaceLayer::Create(new TestSurfaceReferenceFactory( - &satisfied_sequence_, &required_id_, &required_set_)); + ref_factory_ = new testing::StrictMock<MockSurfaceReferenceFactory>(); + + // Create a SurfaceLayer but don't add it to the tree yet. No sequence + // should be required / satisfied. + EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0); + EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0); + layer_ = SurfaceLayer::Create(ref_factory_); SurfaceInfo info( SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)), 1.f, gfx::Size(1, 1)); layer_->SetPrimarySurfaceInfo(info); + testing::Mock::VerifyAndClearExpectations(ref_factory_.get()); - // Layer hasn't been added to tree so no SurfaceSequence generated yet. - EXPECT_EQ(0u, required_set_.size()); - + // Add the layer to the tree. A sequence must be required. + SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u); + SurfaceId expected_id(kArbitraryFrameSinkId, + LocalSurfaceId(1, kArbitraryToken)); + EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0); + EXPECT_CALL(*ref_factory_, + RequireSequence(Eq(expected_id), Eq(expected_seq))) + .Times(1); layer_tree_host()->SetRootLayer(layer_); + testing::Mock::VerifyAndClearExpectations(ref_factory_.get()); - // Should have SurfaceSequence from first tree. - SurfaceSequence expected(kArbitraryFrameSinkId, 1u); - EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId, - LocalSurfaceId(1, kArbitraryToken))); - EXPECT_EQ(1u, required_set_.size()); - EXPECT_TRUE(required_set_.count(expected)); + // By the end of the test, the required sequence must be satisfied and no + // more sequence must be required. + EXPECT_CALL(*ref_factory_, SatisfySequence(Eq(expected_seq))).Times(1); + EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0); gfx::Size bounds(100, 100); layer_tree_host()->SetViewportSize(bounds); @@ -245,15 +237,15 @@ base::Unretained(this))); } + void AfterTest() override {} + protected: int commit_count_; bool sequence_was_satisfied_; scoped_refptr<SurfaceLayer> layer_; scoped_refptr<Layer> blank_layer_; - SurfaceSequence satisfied_sequence_; + scoped_refptr<MockSurfaceReferenceFactory> ref_factory_; - SurfaceId required_id_; - std::set<SurfaceSequence> required_set_; const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create(); }; @@ -276,14 +268,6 @@ break; } } - - void AfterTest() override { - EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId, - LocalSurfaceId(1, kArbitraryToken))); - EXPECT_EQ(1u, required_set_.size()); - EXPECT_TRUE(satisfied_sequence_ == - SurfaceSequence(kArbitraryFrameSinkId, 1u)); - } }; SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw); @@ -315,14 +299,6 @@ break; } } - - void AfterTest() override { - EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId, - LocalSurfaceId(1, kArbitraryToken))); - EXPECT_EQ(1u, required_set_.size()); - EXPECT_TRUE(satisfied_sequence_ == - SurfaceSequence(kArbitraryFrameSinkId, 1u)); - } }; MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithoutDraw);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 3a9b80d..d940da6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1528,13 +1528,12 @@ return true; } - // Close the bottom sheet before trying to navigate back. + // Close the bottom sheet before trying to navigate back. If the tab is on the NTP, fall + // through to decide if the browser should be sent into the background. if (getBottomSheet() != null - && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK) { + && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK + && !(currentTab.getNativePage() instanceof ChromeHomeNewTabPage)) { getBottomSheet().setSheetState(BottomSheet.SHEET_STATE_PEEK, true); - if (currentTab.getNativePage() instanceof ChromeHomeNewTabPage) { - getCurrentTabModel().closeTab(currentTab, true, false, false); - } return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java index 3d61957..1b6af8d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -11,7 +11,6 @@ import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; @@ -28,6 +27,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.widget.selection.SelectableListLayout; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.components.bookmarks.BookmarkId; @@ -244,7 +244,7 @@ /** * See {@link SelectableListLayout#detachToolbarView()}. */ - public Toolbar detachToolbarView() { + public SelectableListToolbar detachToolbarView() { return mSelectableListLayout.detachToolbarView(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java index ba7a661..c76c9e8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.bookmarks; -import android.support.v7.widget.Toolbar; import android.view.View; import org.chromium.chrome.browser.ChromeActivity; @@ -12,24 +11,31 @@ import org.chromium.chrome.browser.toolbar.BottomToolbarPhone; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; /** * A {@link BottomSheetContent} holding a {@link BookmarkManager} for display in the BottomSheet. */ public class BookmarkSheetContent implements BottomSheetContent { private final View mContentView; - private final Toolbar mToolbarView; + private final SelectableListToolbar mToolbarView; private BookmarkManager mBookmarkManager; /** * @param activity The activity displaying the bookmark manager UI. * @param snackbarManager The {@link SnackbarManager} used to display snackbars. */ - public BookmarkSheetContent(ChromeActivity activity, SnackbarManager snackbarManager) { + public BookmarkSheetContent(final ChromeActivity activity, SnackbarManager snackbarManager) { mBookmarkManager = new BookmarkManager(activity, false, snackbarManager); mBookmarkManager.updateForUrl(BookmarkUtils.getLastUsedUrl(activity)); mContentView = mBookmarkManager.getView(); mToolbarView = mBookmarkManager.detachToolbarView(); + mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() { + @Override + public void onThemeColorChanged(boolean isLightTheme) { + activity.getBottomSheet().updateHandleTint(); + } + }); ((BottomToolbarPhone) activity.getToolbarManager().getToolbar()) .setOtherToolbarStyle(mToolbarView); } @@ -45,6 +51,11 @@ } @Override + public boolean isUsingLightToolbarTheme() { + return mToolbarView.isLightTheme(); + } + + @Override public int getVerticalScrollOffset() { return mBookmarkManager.getVerticalScrollOffset(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java index a67c88b..0f074d3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.download; import android.app.Activity; -import android.support.v7.widget.Toolbar; import android.view.View; import org.chromium.base.ActivityState; @@ -18,13 +17,14 @@ import org.chromium.chrome.browser.toolbar.BottomToolbarPhone; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; /** * A {@link BottomSheetContent} holding a {@link DownloadManagerUi} for display in the BottomSheet. */ public class DownloadSheetContent implements BottomSheetContent { private final View mContentView; - private final Toolbar mToolbarView; + private final SelectableListToolbar mToolbarView; private final ActivityStateListener mActivityStateListener; private DownloadManagerUi mDownloadManager; @@ -33,14 +33,20 @@ * @param isIncognito Whether the activity is currently displaying an incognito tab. * @param snackbarManager The {@link SnackbarManager} used to display snackbars. */ - public DownloadSheetContent( - ChromeActivity activity, final boolean isIncognito, SnackbarManager snackbarManager) { + public DownloadSheetContent(final ChromeActivity activity, final boolean isIncognito, + SnackbarManager snackbarManager) { ThreadUtils.assertOnUiThread(); mDownloadManager = new DownloadManagerUi( activity, isIncognito, activity.getComponentName(), false, snackbarManager); mContentView = mDownloadManager.getView(); mToolbarView = mDownloadManager.detachToolbarView(); + mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() { + @Override + public void onThemeColorChanged(boolean isLightTheme) { + activity.getBottomSheet().updateHandleTint(); + } + }); ((BottomToolbarPhone) activity.getToolbarManager().getToolbar()) .setOtherToolbarStyle(mToolbarView); @@ -72,6 +78,11 @@ } @Override + public boolean isUsingLightToolbarTheme() { + return mToolbarView.isLightTheme(); + } + + @Override public int getVerticalScrollOffset() { return mDownloadManager.getVerticalScrollOffset(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java index 366feb3..45bcb76 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -14,7 +14,6 @@ import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; import android.view.Gravity; import android.view.LayoutInflater; @@ -39,6 +38,7 @@ import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; import org.chromium.chrome.browser.widget.selection.SelectableListLayout; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.ui.base.DeviceFormFactor; @@ -305,7 +305,7 @@ /** * See {@link SelectableListLayout#detachToolbarView()}. */ - public Toolbar detachToolbarView() { + public SelectableListToolbar detachToolbarView() { return mSelectableListLayout.detachToolbarView(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java index 9870372..74b4d4f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
@@ -17,7 +17,6 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.OnScrollListener; -import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; import android.view.LayoutInflater; import android.view.MenuItem; @@ -41,6 +40,7 @@ import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.widget.selection.SelectableListLayout; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate.SelectionObserver; @@ -227,7 +227,7 @@ /** * See {@link SelectableListLayout#detachToolbarView()}. */ - public Toolbar detachToolbarView() { + public SelectableListToolbar detachToolbarView() { return mSelectableListLayout.detachToolbarView(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java index 635dffd..0c82317 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.history; -import android.support.v7.widget.Toolbar; import android.view.View; import org.chromium.chrome.browser.ChromeActivity; @@ -12,23 +11,30 @@ import org.chromium.chrome.browser.toolbar.BottomToolbarPhone; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController; +import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; /** * A {@link BottomSheetContent} holding a {@link HistoryManager} for display in the BottomSheet. */ public class HistorySheetContent implements BottomSheetContent { private final View mContentView; - private final Toolbar mToolbarView; + private final SelectableListToolbar mToolbarView; private HistoryManager mHistoryManager; /** * @param activity The activity displaying the history manager UI. * @param snackbarManager The {@link SnackbarManager} used to display snackbars. */ - public HistorySheetContent(ChromeActivity activity, SnackbarManager snackbarManager) { + public HistorySheetContent(final ChromeActivity activity, SnackbarManager snackbarManager) { mHistoryManager = new HistoryManager(activity, false, snackbarManager); mContentView = mHistoryManager.getView(); mToolbarView = mHistoryManager.detachToolbarView(); + mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() { + @Override + public void onThemeColorChanged(boolean isLightTheme) { + activity.getBottomSheet().updateHandleTint(); + } + }); ((BottomToolbarPhone) activity.getToolbarManager().getToolbar()) .setOtherToolbarStyle(mToolbarView); } @@ -44,6 +50,11 @@ } @Override + public boolean isUsingLightToolbarTheme() { + return mToolbarView.isLightTheme(); + } + + @Override public int getVerticalScrollOffset() { return mHistoryManager.getVerticalScrollOffset(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java index 465102a..ced1746 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
@@ -71,6 +71,11 @@ } @Override + public boolean isUsingLightToolbarTheme() { + return false; + } + + @Override public int getVerticalScrollOffset() { return mScrollView.getScrollY(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 6c01ec4..b232c7f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -22,6 +22,7 @@ import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate; import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.page_info.CertificateChainHelper; import org.chromium.chrome.browser.payments.ui.Completable; @@ -84,11 +85,12 @@ * Android implementation of the PaymentRequest service defined in * components/payments/content/payment_request.mojom. */ -public class PaymentRequestImpl - implements PaymentRequest, PaymentRequestUI.Client, PaymentApp.InstrumentsCallback, - PaymentInstrument.InstrumentDetailsCallback, - PaymentAppFactory.PaymentAppCreatedCallback, - PaymentResponseHelper.PaymentResponseRequesterDelegate, FocusChangedObserver { +public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Client, + PaymentApp.InstrumentsCallback, + PaymentInstrument.InstrumentDetailsCallback, + PaymentAppFactory.PaymentAppCreatedCallback, + PaymentResponseHelper.PaymentResponseRequesterDelegate, + FocusChangedObserver, NormalizedAddressRequestDelegate { /** * A test-only observer for the PaymentRequest service implementation. */ @@ -974,8 +976,7 @@ AutofillAddress address = (AutofillAddress) option; if (address.isComplete()) { mShippingAddressesSection.setSelectedItem(option); - // This updates the line items and the shipping options asynchronously. - mClient.onShippingAddressChange(address.toPaymentAddress()); + startShippingAddressChangeNormalization(address); } else { editAddress(address); } @@ -1110,9 +1111,7 @@ PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection); } - // This updates the line items and the shipping options asynchronously by - // sending the new address to the merchant website. - mClient.onShippingAddressChange(editedAddress.toPaymentAddress()); + startShippingAddressChangeNormalization(editedAddress); } } else { providePaymentInformation(); @@ -1593,6 +1592,38 @@ mUI.updateSection(PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, mShippingAddressesSection); } + @Override + public void onAddressNormalized(AutofillProfile profile) { + ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents); + + // Can happen if the tab is closed during the normalization process. + if (chromeActivity == null) { + recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_OTHER); + disconnectFromClientWithDebugMessage("Unable to find Chrome activity"); + if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed(); + return; + } + + // Don't reuse the selected address because it is formatted for display. + AutofillAddress shippingAddress = new AutofillAddress(chromeActivity, profile); + + // This updates the line items and the shipping options asynchronously. + mClient.onShippingAddressChange(shippingAddress.toPaymentAddress()); + } + + @Override + public void onCouldNotNormalize(AutofillProfile profile) { + // Since the phone number is formatted in either case, this profile should be used. + onAddressNormalized(profile); + } + + /** Starts the normalization of the new shipping address. Will call back into either + * onAddressNormalized or onCouldNotNormalize which will send the result to the merchant. */ + private void startShippingAddressChangeNormalization(AutofillAddress address) { + PersonalDataManager.getInstance().normalizeAddress( + address.getProfile(), AutofillAddress.getCountryCode(address.getProfile()), this); + } + /** * Closes the UI. If the client is still connected, then it's notified of UI hiding. *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java index 011b54f..9d6131f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -139,6 +139,11 @@ } @Override + public boolean isUsingLightToolbarTheme() { + return false; + } + + @Override public int getVerticalScrollOffset() { return mRecyclerView.computeVerticalScrollOffset(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java index 314eebe2..26b0d8cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -119,6 +119,21 @@ context.getResources(), R.drawable.toolbar_handle_light); } + /** + * Set the color of the pull handle used by the toolbar. + * @param useLightDrawable If the handle color should be light. + */ + public void updateHandleTint(boolean useLightDrawable) { + mToolbarHandleView.setImageDrawable(useLightDrawable ? mHandleLight : mHandleDark); + } + + /** + * @return Whether or not the toolbar is currently using a light theme color. + */ + public boolean isLightTheme() { + return !ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor()); + } + @Override protected int getProgressBarTopMargin() { // In the case where the toolbar is at the bottom of the screen, the progress bar should @@ -235,8 +250,7 @@ // The tab switcher's background color should not affect the toolbar handle; it should only // switch color based on the static tab's theme color. This is done so fade in/out looks // correct. - boolean isLight = ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor()); - mToolbarHandleView.setImageDrawable(isLight ? mHandleLight : mHandleDark); + mToolbarHandleView.setImageDrawable(isLightTheme() ? mHandleDark : mHandleLight); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index 36c00f1..97b0e44 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.toolbar.BottomToolbarPhone; import org.chromium.chrome.browser.util.MathUtils; import org.chromium.chrome.browser.widget.FadingBackgroundView; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController.ContentType; @@ -193,7 +194,7 @@ * The default toolbar view. This is shown when the current bottom sheet content doesn't have * its own toolbar and when the bottom sheet is closed. */ - private View mDefaultToolbarView; + private BottomToolbarPhone mDefaultToolbarView; /** Whether the {@link BottomSheet} and its children should react to touch events. */ private boolean mIsTouchEnabled = true; @@ -227,6 +228,11 @@ View getToolbarView(); /** + * @return Whether or not the toolbar is currently using a lightly colored background. + */ + boolean isUsingLightToolbarTheme(); + + /** * @return The vertical scroll offset of the content view. */ int getVerticalScrollOffset(); @@ -555,7 +561,22 @@ mBottomSheetContentContainer.addView(mPlaceholder, placeHolderParams); mToolbarHolder = (FrameLayout) mControlContainer.findViewById(R.id.toolbar_holder); - mDefaultToolbarView = mControlContainer.findViewById(R.id.toolbar); + mDefaultToolbarView = (BottomToolbarPhone) mControlContainer.findViewById(R.id.toolbar); + } + + /** + * Set the color of the pull handle used by the toolbar. + */ + public void updateHandleTint() { + boolean isLightToolbarTheme = mDefaultToolbarView.isLightTheme(); + + // If the current sheet content's toolbar is using a special theme, use that. + if (mSheetContent != null && mSheetContent.getToolbarView() != null) { + isLightToolbarTheme = mSheetContent.isUsingLightToolbarTheme(); + } + + // A light toolbar theme means the handle should be dark. + mDefaultToolbarView.updateHandleTint(!isLightToolbarTheme); } @Override @@ -696,6 +717,7 @@ currentToolbar.setVisibility(View.GONE); } mToolbarFadeAnimator = null; + updateHandleTint(); } });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java index 89a815ee..82bda12 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
@@ -17,7 +17,6 @@ import android.support.v7.widget.RecyclerView.AdapterDataObserver; import android.support.v7.widget.RecyclerView.ItemAnimator; import android.support.v7.widget.RecyclerView.OnScrollListener; -import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; import android.util.AttributeSet; import android.view.Gravity; @@ -315,7 +314,7 @@ * elsewhere. * @return The toolbar view. */ - public Toolbar detachToolbarView() { + public SelectableListToolbar detachToolbarView() { removeView(mToolbar); // The top margin for the content and shadow needs to be removed now that the toolbar
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java index 74c5980..a483eb00 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
@@ -27,6 +27,7 @@ import android.widget.TextView.OnEditorActionListener; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ObserverList; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.widget.NumberRollView; @@ -68,6 +69,18 @@ void onEndSearch(); } + /** + * An interface to observe events on this toolbar. + */ + public interface SelectableListToolbarObserver { + /** + * A notification that the theme color of the toolbar has changed. + * @param isLightTheme Whether or not the toolbar is using a light theme. When this + * parameter is true, it indicates that dark drawables should be used. + */ + void onThemeColorChanged(boolean isLightTheme); + } + /** No navigation button is displayed. **/ protected static final int NAVIGATION_BUTTON_NONE = 0; /** Button to open the DrawerLayout. Only valid if mDrawerLayout is set. **/ @@ -77,6 +90,9 @@ /** Button to clear the selection. **/ protected static final int NAVIGATION_BUTTON_SELECTION_BACK = 3; + /** An observer list for this toolbar. */ + private final ObserverList<SelectableListToolbarObserver> mObservers = new ObserverList<>(); + protected boolean mIsSelectionEnabled; protected SelectionDelegate<E> mSelectionDelegate; protected boolean mIsSearching; @@ -86,6 +102,7 @@ private EditText mSearchEditText; private TintedImageButton mClearTextButton; private SearchDelegate mSearchDelegate; + private boolean mIsLightTheme = true; protected NumberRollView mNumberRollView; private DrawerLayout mDrawerLayout; @@ -128,6 +145,7 @@ void destroy() { mIsDestroyed = true; if (mSelectionDelegate != null) mSelectionDelegate.removeObserver(this); + mObservers.clear(); UiUtils.hideKeyboard(mSearchEditText); } @@ -483,6 +501,20 @@ } /** + * @return Whether or not the toolbar is currently using a light theme. + */ + public boolean isLightTheme() { + return mIsLightTheme; + } + + /** + * @param observer The observer to add to this toolbar. + */ + public void addObserver(SelectableListToolbarObserver observer) { + mObservers.addObserver(observer); + } + + /** * Set up ActionBarDrawerToggle, a.k.a. hamburger button. */ private void initActionBarDrawerToggle() { @@ -509,6 +541,7 @@ mNumberRollView.setVisibility(View.GONE); mNumberRollView.setNumber(0, false); + onThemeChanged(true); updateDisplayStyleIfNecessary(); } @@ -528,6 +561,7 @@ if (mIsSearching) UiUtils.hideKeyboard(mSearchEditText); + onThemeChanged(false); updateDisplayStyleIfNecessary(); } @@ -539,9 +573,19 @@ setNavigationButton(NAVIGATION_BUTTON_BACK); setBackgroundColor(mSearchBackgroundColor); + onThemeChanged(true); updateDisplayStyleIfNecessary(); } + /** + * Update internal state and notify observers that the theme color changed. + * @param isLightTheme Whether or not the theme color is light. + */ + private void onThemeChanged(boolean isLightTheme) { + mIsLightTheme = isLightTheme; + for (SelectableListToolbarObserver o : mObservers) o.onThemeColorChanged(isLightTheme); + } + private void updateDisplayStyleIfNecessary() { if (mUiConfig != null) onDisplayStyleChanged(mUiConfig.getCurrentDisplayStyle()); }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 08fb529d..67973c3 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1508,6 +1508,7 @@ "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java", + "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java index bdeecda..6c9620e4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -24,12 +24,12 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.test.ChromeTabbedActivityTestBase; -import org.chromium.chrome.test.MultiActivityTestBase; import org.chromium.chrome.test.util.ApplicationTestUtils; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.content.browser.test.util.Criteria; @@ -633,9 +633,25 @@ } })); + // Defines one gigantic link spanning the whole page that creates a new + // window with chrome/test/data/android/google.html. + final String hrefLink = UrlUtils.encodeHtmlDataUri("<html>" + + " <head>" + + " <title>href link page</title>" + + " <meta name='viewport'" + + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" + + " <style>" + + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" + + " </style>" + + " </head>" + + " <body>" + + " <a href='" + mTestServer.getURL("/chrome/test/data/android/google.html") + + "' target='_blank'><div></div></a>" + + " </body>" + + "</html>"); + // Open a tab via an external application. - final Intent intent = new Intent( - Intent.ACTION_VIEW, Uri.parse(MultiActivityTestBase.HREF_LINK)); + final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(hrefLink)); intent.setClassName(getInstrumentation().getTargetContext().getPackageName(), ChromeTabbedActivity.class.getName()); intent.putExtra(Browser.EXTRA_APPLICATION_ID, "com.legit.totes");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java new file mode 100644 index 0000000..4491c2c --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
@@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.payments; + +import android.support.test.filters.MediumTest; + +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.autofill.AutofillTestHelper; +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * A payment integration test for a merchant that requires shipping address to calculate shipping. + */ +public class PaymentRequestShippingAddressChangeTest extends PaymentRequestTestBase { + public PaymentRequestShippingAddressChangeTest() { + // This merchant requests the shipping address first before providing any shipping options. + // The result printed from this site is the shipping address change, not the Payment + // Response. + super("payment_request_shipping_address_change_test.html"); + } + + @Override + public void onMainActivityStarted() + throws InterruptedException, ExecutionException, TimeoutException { + AutofillTestHelper helper = new AutofillTestHelper(); + // The user has a shipping address on disk. + String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com", + true, "Jon Doe", "Google", "340 Main St", "California", "Los Angeles", "", "90291", + "", "US", "650-253-0000", "", "en-US")); + helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe", + "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa, + billingAddressId, "" /* serverId */)); + } + + /** + * Tests the format of the shipping address that is sent to the merchant when the user changes + * the shipping address selection. + */ + @MediumTest + @Feature({"Payments"}) + public void testShippingAddressChangeFormat() + throws InterruptedException, ExecutionException, TimeoutException { + // Select a shipping address and cancel out. + triggerUIAndWait(mReadyForInput); + clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput); + clickOnShippingAddressSuggestionOptionAndWait(0, mReadyForInput); + clickAndWait(R.id.close_button, mDismissed); + + // The phone number should be formatted to the internation format. + expectResultContains(new String[] {"Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", + "90291", "+16502530000", "US"}); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java index a1b13303..540f792a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
@@ -33,6 +33,7 @@ import org.chromium.content.browser.test.util.JavaScriptUtils; import org.chromium.content.browser.test.util.TouchCommon; import org.chromium.content_public.common.ScreenOrientationValues; +import org.chromium.net.test.EmbeddedTestServer; /** * Tests that WebappActivities are launched correctly. @@ -61,6 +62,8 @@ + "IWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wQIFB4cxOfiSQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdG" + "ggR0lNUFeBDhcAAAAMSURBVAjXY2AUawEAALcAnI/TkI8AAAAASUVORK5CYII="; + private EmbeddedTestServer mTestServer; + private Intent createIntent(String id, String url, String title, String icon, boolean addMac) { Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -115,6 +118,14 @@ WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON, true)); } }); + + mTestServer = EmbeddedTestServer.createAndStartServer(getInstrumentation().getContext()); + } + + @Override + public void tearDown() throws Exception { + mTestServer.stopAndDestroyServer(); + super.tearDown(); } /** @@ -245,7 +256,7 @@ @MediumTest @Feature({"Webapps"}) public void testWebappHandlesWindowOpenInTabbedMode() throws Exception { - triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, ONCLICK_LINK, true); + triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, getOnClickLinkUrl(), true); } /** @@ -254,7 +265,8 @@ @MediumTest @Feature({"Webapps"}) public void testWebappHandlesSuppressedWindowOpenInTabbedMode() throws Exception { - triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, HREF_NO_REFERRER_LINK, false); + triggerWindowOpenAndWaitForLoad( + ChromeTabbedActivity.class, getHrefNoReferrerLinkUrl(), false); } private <T extends ChromeActivity> void triggerWindowOpenAndWaitForLoad( @@ -283,10 +295,10 @@ }; ChromeActivity secondActivity = ActivityUtils.waitForActivity( getInstrumentation(), classToWaitFor, fgTrigger); - waitForFullLoad(secondActivity, "Page 4"); + waitForFullLoad(secondActivity, "The Google"); if (checkContents) { - assertEquals("New WebContents was not created", - SUCCESS_URL, firstActivity.getActivityTab().getUrl()); + assertEquals("New WebContents was not created", "SUCCESS", + firstActivity.getActivityTab().getTitle()); } assertNotSame("Wrong Activity in foreground", firstActivity, ApplicationStatus.getLastTrackedFocusedActivity()); @@ -336,4 +348,49 @@ return true; } + + /** Defines one gigantic link spanning the whole page that creates a new + * window with chrome/test/data/android/google.html. Disallowing a referrer from being + * sent triggers another codepath. + */ + private String getHrefNoReferrerLinkUrl() { + return UrlUtils.encodeHtmlDataUri("<html>" + + " <head>" + + " <title>href no referrer link page</title>" + + " <meta name='viewport'" + + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" + + " <style>" + + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" + + " </style>" + + " </head>" + + " <body>" + + " <a href='" + mTestServer.getURL("/chrome/test/data/android/google.html") + + "' target='_blank' rel='noreferrer'><div></div></a>" + + " </body>"); + } + + /** Returns a URL where clicking the body triggers a window.open() call to open + * chrome/test/data/android/google.html. */ + private String getOnClickLinkUrl() { + return UrlUtils.encodeHtmlDataUri("<html>" + + " <head>" + + " <title>window.open page</title>" + + " <meta name='viewport'" + + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" + + " <style>" + + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" + + " </style>" + + " <script>" + + " function openNewWindow() {" + + " var site = window.open('" + + mTestServer.getURL("/chrome/test/data/android/google.html") + "');" + + " document.title = site ? 'SUCCESS' : 'FAILURE';" + + " }" + + " </script>" + + " </head>" + + " <body id='body'>" + + " <div onclick='openNewWindow()'></div>" + + " </body>" + + "</html>"); + } }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java index d09e427..aebb750 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -15,9 +15,12 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.chrome.browser.TabState; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; +import org.chromium.components.sync.SyncConstants; import org.chromium.components.sync.protocol.EntitySpecifics; import org.chromium.components.sync.protocol.SessionHeader; import org.chromium.components.sync.protocol.SessionSpecifics; @@ -177,6 +180,26 @@ waitForLocalTabsForClient(FAKE_CLIENT); } + // Test + @LargeTest + @Feature({"Sync"}) + public void testTabGetsValidSyncId() throws Exception { + Tab tab = loadUrlInNewTab(URL); + + TabState state = tab.getState(); + assertFalse(state.syncId == SyncConstants.INVALID_TAB_NODE_ID); + } + + // Test + @LargeTest + @Feature({"Sync"}) + public void testIncognitoTabGetsInvalidSyncId() throws Exception { + Tab tab = loadUrlInNewTab(URL, /*incognito=*/true); + + TabState state = tab.getState(); + assertEquals(state.syncId, SyncConstants.INVALID_TAB_NODE_ID); + } + private String makeSessionTag() { return SESSION_TAG_PREFIX + (mSessionTagCounter++); }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 9c25080..4936da7 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -1926,13 +1926,32 @@ desc="Text for the search button in the touch bar when Google is not the default search provider. Pressing the button will bring focus to the omnibox. $1 is the name of the search provider)"> Search <ph name="SEARCH_ENGINE">$1<ex>Bing</ex></ph> </message> - <message name="IDS_TOOLTIP_TOUCH_BAR_BACK" desc="The tooltip for the touch bar back button."> Touch to go back. </message> <message name="IDS_TOOLTIP_TOUCH_BAR_FORWARD" desc="The tooltip for the touch bar forward button."> Touch to go forward. </message> + <message name="IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL" + desc="Customization label for the back and forward buttons in the touch bar."> + Back/Forward + </message> + <message name="IDS_TOUCH_BAR_STOP_RELOAD_CUSTOMIZATION_LABEL" + desc="Customization label for the stop or reload button in the touch bar."> + Stop/Reload + </message> + <message name="IDS_TOUCH_BAR_HOME_CUSTOMIZATION_LABEL" + desc="Customization label for the home button in the touch bar."> + Home + </message> + <message name="IDS_TOUCH_BAR_BOOKMARK_CUSTOMIZATION_LABEL" + desc="Customization label for the bookmark button in the touch bar."> + Bookmark + </message> + <message name="IDS_TOUCH_BAR_NEW_TAB_CUSTOMIZATION_LABEL" + desc="Customization label for the new tab button in the touch bar."> + New Tab + </message> </if> <!-- Remove in-progress downloads confirmation dialog -->
diff --git a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc index 18e2ec2..d4ca0340 100644 --- a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc +++ b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc
@@ -30,9 +30,10 @@ /* clang-format off */ const char kQuadCopyVertex[] = SHADER( + precision mediump float; attribute vec4 a_Position; attribute vec2 a_TexCoordinate; - varying vec2 v_TexCoordinate; + varying highp vec2 v_TexCoordinate; void main() { v_TexCoordinate = a_TexCoordinate; gl_Position = a_Position;
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc index 7951074d..262116cb 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -77,6 +77,7 @@ case vr_shell::ShaderID::CONTROLLER_VERTEX_SHADER: return SHADER( /* clang-format off */ + precision mediump float; uniform mat4 u_ModelViewProjMatrix; attribute vec4 a_Position; attribute vec2 a_TexCoordinate; @@ -91,6 +92,7 @@ case vr_shell::ShaderID::GRADIENT_GRID_VERTEX_SHADER: return SHADER( /* clang-format off */ + precision mediump float; uniform mat4 u_ModelViewProjMatrix; uniform float u_SceneRadius; attribute vec4 a_Position; @@ -122,9 +124,10 @@ case vr_shell::ShaderID::WEBVR_VERTEX_SHADER: return SHADER( /* clang-format off */ + precision mediump float; attribute vec3 a_Position; attribute vec2 a_TexCoordinate; - varying vec2 v_TexCoordinate; + varying highp vec2 v_TexCoordinate; void main() { v_TexCoordinate = a_TexCoordinate; @@ -145,6 +148,7 @@ case vr_shell::ShaderID::RETICLE_FRAGMENT_SHADER: return SHADER( /* clang-format off */ + precision mediump float; varying mediump vec2 v_TexCoordinate; uniform lowp vec4 color; uniform mediump float ring_diameter; @@ -218,6 +222,7 @@ case vr_shell::ShaderID::CONTROLLER_FRAGMENT_SHADER: return SHADER( /* clang-format off */ + precision mediump float; uniform sampler2D u_texture; varying vec2 v_TexCoordinate;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 78d27e24..f6e6ec57 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -741,6 +741,12 @@ handoff_active_url_observer_bridge_.reset( new HandoffActiveURLObserverBridge(self)); + + NSApplication* application = [NSApplication sharedApplication]; + if ([application respondsToSelector: + @selector(setAutomaticCustomizeTouchBarMenuItemEnabled:)]) { + [application setAutomaticCustomizeTouchBarMenuItemEnabled:YES]; + } } // Helper function for populating and displaying the in progress downloads at
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc index f12f6f06..4971fa68 100644 --- a/chrome/browser/chrome_navigation_browsertest.cc +++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -189,6 +189,119 @@ new_web_contents->GetTitle()); } +// Tests that verify that ctrl-click results 1) open up in a new renderer +// process (https://crbug.com/23815) and 2) are in a new browsing instance (e.g. +// cannot find the opener's window by name - https://crbug.com/658386). +class CtrlClickShouldEndUpInNewProcessTest + : public ChromeNavigationBrowserTest { + protected: + // Simulates ctrl-clicking an anchor with the given id in |main_contents|. + // Verifies that the new contents are in a separate process and separate + // browsing instance from |main_contents|. Returns contents of the newly + // opened tab. + content::WebContents* SimulateCtrlClick(content::WebContents* main_contents, + const char* id_of_anchor_to_click) { + // Ctrl-click the anchor/link in the page. + content::WebContents* new_contents = nullptr; + { + content::WebContentsAddedObserver new_tab_observer; +#if defined(OS_MACOSX) + const char* new_tab_click_script_template = + "simulateClick(\"%s\", { metaKey: true });"; +#else + const char* new_tab_click_script_template = + "simulateClick(\"%s\", { ctrlKey: true });"; +#endif + std::string new_tab_click_script = base::StringPrintf( + new_tab_click_script_template, id_of_anchor_to_click); + EXPECT_TRUE(ExecuteScript(main_contents, new_tab_click_script)); + + // Wait for a new tab to appear (the whole point of this test). + new_contents = new_tab_observer.GetWebContents(); + } + + // Verify that the new tab has the right contents and is in the right, new + // place in the tab strip. + EXPECT_TRUE(WaitForLoadStop(new_contents)); + int last_tab_index = browser()->tab_strip_model()->count() - 1; + EXPECT_LT(1, browser()->tab_strip_model()->count()); // More than 1 tab? + EXPECT_EQ(new_contents, + browser()->tab_strip_model()->GetWebContentsAt(last_tab_index)); + GURL expected_url(embedded_test_server()->GetURL("/title1.html")); + EXPECT_EQ(expected_url, new_contents->GetLastCommittedURL()); + + // Verify that the new tab is in a different process, SiteInstance and + // BrowsingInstance from the old contents. + EXPECT_NE(main_contents->GetMainFrame()->GetProcess(), + new_contents->GetMainFrame()->GetProcess()); + EXPECT_NE(main_contents->GetMainFrame()->GetSiteInstance(), + new_contents->GetMainFrame()->GetSiteInstance()); + EXPECT_FALSE(main_contents->GetSiteInstance()->IsRelatedSiteInstance( + new_contents->GetSiteInstance())); + + // Verify that the new BrowsingInstance can't see windows from the old one. + { + // Double-check that main_contents has expected window.name set. + // This is a sanity check of test setup; this is not a product test. + std::string name_of_main_contents_window; + EXPECT_TRUE(ExecuteScriptAndExtractString( + main_contents, "window.domAutomationController.send(window.name)", + &name_of_main_contents_window)); + EXPECT_EQ("main_contents", name_of_main_contents_window); + + // Verify that the new contents doesn't have a window.opener set. + bool window_opener_cast_to_bool; + EXPECT_TRUE(ExecuteScriptAndExtractBool( + new_contents, "window.domAutomationController.send(!!window.opener)", + &window_opener_cast_to_bool)); + EXPECT_FALSE(window_opener_cast_to_bool); + + // Verify that the new contents cannot find the old contents via + // window.open. (i.e. window.open should open a new window, rather than + // returning a reference to main_contents / old window). + std::string location_of_opened_window; + EXPECT_TRUE(ExecuteScriptAndExtractString( + new_contents, + "w = window.open('', 'main_contents');" + "window.domAutomationController.send(w.location.href);", + &location_of_opened_window)); + EXPECT_EQ(url::kAboutBlankURL, location_of_opened_window); + } + + return new_contents; + } +}; + +IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, NoTarget) { + // Navigate to the test page. + GURL main_url(embedded_test_server()->GetURL( + "/frame_tree/anchor_to_same_site_location.html")); + ui_test_utils::NavigateToURL(browser(), main_url); + const char* kIdOfAnchorToClick = "test-anchor-no-target"; + + // Verify that there is only 1 active tab (with the right contents committed). + EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); + content::WebContents* main_contents = + browser()->tab_strip_model()->GetWebContentsAt(0); + EXPECT_EQ(main_url, main_contents->GetLastCommittedURL()); + + // Test what happens after ctrl-click. SimulateCtrlClick will verify + // that |new_contents1| is in a separate process and browsing instance + // from |main_contents|. + content::WebContents* new_contents1 = + SimulateCtrlClick(main_contents, kIdOfAnchorToClick); + + // Test that each subsequent ctrl-click also gets a new process. + content::WebContents* new_contents2 = + SimulateCtrlClick(main_contents, kIdOfAnchorToClick); + EXPECT_NE(new_contents1->GetMainFrame()->GetProcess(), + new_contents2->GetMainFrame()->GetProcess()); + EXPECT_NE(new_contents1->GetMainFrame()->GetSiteInstance(), + new_contents2->GetMainFrame()->GetSiteInstance()); + EXPECT_FALSE(new_contents1->GetSiteInstance()->IsRelatedSiteInstance( + new_contents2->GetSiteInstance())); +} + class ChromeNavigationPortMappedBrowserTest : public InProcessBrowserTest { public: ChromeNavigationPortMappedBrowserTest() {}
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc index 5666ce3b..c1ca630 100644 --- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc +++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -41,6 +41,10 @@ } // namespace // static +const char ArcVoiceInteractionFrameworkService::kArcServiceName[] = + "arc::ArcVoiceInteractionFrameworkService"; + +// static bool ArcVoiceInteractionFrameworkService::IsVoiceInteractionEnabled() { return base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kEnableVoiceInteraction); @@ -75,6 +79,8 @@ void ArcVoiceInteractionFrameworkService::OnInstanceClosed() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); ash::Shell::Get()->accelerator_controller()->UnregisterAll(this); + if (!metalayer_closed_callback_.is_null()) + base::ResetAndReturn(&metalayer_closed_callback_).Run(); } bool ArcVoiceInteractionFrameworkService::AcceleratorPressed( @@ -82,12 +88,14 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (accelerator.IsShiftDown()) { + // Temporary, used for debugging. + // Does not take into account or update the palette state. mojom::VoiceInteractionFrameworkInstance* framework_instance = ARC_GET_INSTANCE_FOR_METHOD( arc_bridge_service()->voice_interaction_framework(), - ToggleMetalayer); + SetMetalayerVisibility); DCHECK(framework_instance); - framework_instance->ToggleMetalayer(); + framework_instance->SetMetalayerVisibility(true); } else { mojom::VoiceInteractionFrameworkInstance* framework_instance = ARC_GET_INSTANCE_FOR_METHOD( @@ -136,4 +144,54 @@ base::Bind(&ScreenshotCallback, callback)); } +void ArcVoiceInteractionFrameworkService::OnMetalayerClosed() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!metalayer_closed_callback_.is_null()) + base::ResetAndReturn(&metalayer_closed_callback_).Run(); +} + +bool ArcVoiceInteractionFrameworkService::IsMetalayerSupported() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + mojom::VoiceInteractionFrameworkInstance* framework_instance = + ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service()->voice_interaction_framework(), + SetMetalayerVisibility); + return framework_instance; +} + +void ArcVoiceInteractionFrameworkService::ShowMetalayer( + const base::Closure& closed) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!metalayer_closed_callback_.is_null()) { + LOG(ERROR) << "Metalayer is already enabled"; + return; + } + metalayer_closed_callback_ = closed; + SetMetalayerVisibility(true); +} + +void ArcVoiceInteractionFrameworkService::HideMetalayer() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (metalayer_closed_callback_.is_null()) { + LOG(ERROR) << "Metalayer is already hidden"; + return; + } + metalayer_closed_callback_ = base::Closure(); + SetMetalayerVisibility(false); +} + +void ArcVoiceInteractionFrameworkService::SetMetalayerVisibility(bool visible) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + mojom::VoiceInteractionFrameworkInstance* framework_instance = + ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service()->voice_interaction_framework(), + SetMetalayerVisibility); + if (!framework_instance) { + if (!metalayer_closed_callback_.is_null()) + base::ResetAndReturn(&metalayer_closed_callback_).Run(); + return; + } + framework_instance->SetMetalayerVisibility(visible); +} + } // namespace arc
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h index 015acf8..71583e3a 100644 --- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h +++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
@@ -42,12 +42,23 @@ void CaptureFocusedWindow( const CaptureFocusedWindowCallback& callback) override; void CaptureFullscreen(const CaptureFullscreenCallback& callback) override; + void OnMetalayerClosed() override; + + bool IsMetalayerSupported(); + void ShowMetalayer(const base::Closure& closed); + void HideMetalayer(); // Whether enable-voice-interaction switch is present. static bool IsVoiceInteractionEnabled(); + // For supporting ArcServiceManager::GetService<T>(). + static const char kArcServiceName[]; + private: + void SetMetalayerVisibility(bool visible); + mojo::Binding<mojom::VoiceInteractionFrameworkHost> binding_; + base::Closure metalayer_closed_callback_; DISALLOW_COPY_AND_ASSIGN(ArcVoiceInteractionFrameworkService); };
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc index f47bd70..f0de2b0 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
@@ -23,6 +23,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/browser_context.h" #include "extensions/browser/api_test_utils.h" +#include "extensions/browser/extension_function_registry.h" #include "extensions/common/extension.h" #include "extensions/test/result_catcher.h" #include "storage/browser/fileapi/external_mount_points.h" @@ -69,6 +70,12 @@ EXPECT_EQ(expected_contents, test_file_contents); } +bool OverrideFunction(const std::string& name, + extensions::ExtensionFunctionFactory factory) { + return ExtensionFunctionRegistry::GetInstance()->OverrideFunctionForTesting( + name, factory); +} + // Mocks FileSelector used by FileBrowserHandlerInternalSelectFileFunction. // When |SelectFile| is called, it will check that file name suggestion is as // expected, and respond to the extension function with specified selection @@ -267,7 +274,7 @@ SetTestCases(&test_cases); // Override extension function that will be used during the test. - ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( + ASSERT_TRUE(OverrideFunction( "fileBrowserHandlerInternal.selectFile", FileBrowserHandlerExtensionTest::TestSelectFileFunctionFactory));
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc index 49de8135..e67e5992a 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -9,7 +9,6 @@ #include "ash/shell.h" #include "ash/wallpaper/wallpaper_controller.h" -#include "ash/wm/lock_state_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" @@ -157,12 +156,6 @@ bundle.GetRawDataResource(IDR_SOUND_LOCK_WAV)); manager->Initialize(SOUND_UNLOCK, bundle.GetRawDataResource(IDR_SOUND_UNLOCK_WAV)); - - ash::Shell::Get()->lock_state_controller()->SetLockScreenDisplayedCallback( - base::Bind(base::IgnoreResult(&AccessibilityManager::PlayEarcon), - base::Unretained(AccessibilityManager::Get()), - chromeos::SOUND_LOCK, - PlaySoundOption::SPOKEN_FEEDBACK_ENABLED)); } void ScreenLocker::Init() { @@ -182,6 +175,10 @@ new ScreenlockIconSource(screenlock_icon_provider_->AsWeakPtr()); content::URLDataSource::Add(web_ui()->GetWebContents()->GetBrowserContext(), screenlock_icon_source); + + // Start locking on ash side. + SessionControllerClient::Get()->StartLock(base::Bind( + &ScreenLocker::OnStartLockCallback, weak_factory_.GetWeakPtr())); } void ScreenLocker::OnAuthFailure(const AuthFailure& error) { @@ -355,6 +352,19 @@ return nullptr; } +void ScreenLocker::OnStartLockCallback(bool locked) { + // Happens in tests that exit with a pending lock. In real lock failure, + // ash::LockStateController would cause the current user session to be + // terminated. + if (!locked) + return; + + web_ui()->OnLockAnimationFinished(); + + AccessibilityManager::Get()->PlayEarcon( + chromeos::SOUND_LOCK, PlaySoundOption::SPOKEN_FEEDBACK_ENABLED); +} + void ScreenLocker::ClearErrors() { web_ui()->ClearErrors(); } @@ -412,7 +422,6 @@ if (g_screen_lock_observer->session_started() && user_manager::UserManager::Get()->CanCurrentUserLock()) { ScreenLocker::Show(); - ash::Shell::Get()->lock_state_controller()->OnStartingLock(); } else { // If the current user's session cannot be locked or the user has not // completed all sign-in steps yet, log out instead. The latter is done to
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.h b/chrome/browser/chromeos/login/lock/screen_locker.h index 07f65bb99..e15ecd6 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker.h +++ b/chrome/browser/chromeos/login/lock/screen_locker.h
@@ -145,6 +145,11 @@ // Looks up user in unlock user list. const user_manager::User* FindUnlockUser(const AccountId& account_id); + // Callback to be invoked for ash start lock request. |locked| is true when + // ash is fully locked and post lock animation finishes. Otherwise, the start + // lock request is failed. + void OnStartLockCallback(bool locked); + // WebUIScreenLocker instance in use. std::unique_ptr<WebUIScreenLocker> web_ui_;
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc index e4c0251..8b87e22 100644 --- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -5,7 +5,6 @@ #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h" #include "ash/shell.h" -#include "ash/shell_port.h" #include "ash/system/power/power_event_observer.h" #include "base/command_line.h" #include "base/feature_list.h" @@ -124,7 +123,6 @@ network_state_helper_(new login::NetworkStateHelper), weak_factory_(this) { set_should_emit_login_prompt_visible(false); - ash::ShellPort::Get()->AddLockStateObserver(this); display::Screen::GetScreen()->AddObserver(this); DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); } @@ -132,7 +130,6 @@ WebUIScreenLocker::~WebUIScreenLocker() { DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); display::Screen::GetScreen()->RemoveObserver(this); - ash::ShellPort::Get()->RemoveLockStateObserver(this); // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker. if (lock_window_) { lock_window_->RemoveObserver(this); @@ -261,6 +258,14 @@ ash::Shell::Get()->power_event_observer()->OnLockAnimationsComplete(); } +void WebUIScreenLocker::OnLockAnimationFinished() { + // Release capture if any. + aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow()) + ->SetCapture(nullptr); + GetWebUI()->CallJavascriptFunctionUnsafe( + "cr.ui.Oobe.animateOnceFullyDisplayed"); +} + //////////////////////////////////////////////////////////////////////////////// // WebUIScreenLocker, LoginDisplay::Delegate: @@ -344,25 +349,11 @@ } //////////////////////////////////////////////////////////////////////////////// -// SessionLockStateObserver: - -void WebUIScreenLocker::OnLockStateEvent( - ash::LockStateObserver::EventType event) { - if (event == ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED) { - // Release capture if any. - aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())-> - SetCapture(NULL); - GetWebUI()->CallJavascriptFunctionUnsafe( - "cr.ui.Oobe.animateOnceFullyDisplayed"); - } -} - -//////////////////////////////////////////////////////////////////////////////// // WidgetObserver: void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { lock_window_->RemoveObserver(this); - lock_window_ = NULL; + lock_window_ = nullptr; } ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.h b/chrome/browser/chromeos/login/lock/webui_screen_locker.h index fea1b72..b8b87180 100644 --- a/chrome/browser/chromeos/login/lock/webui_screen_locker.h +++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
@@ -10,7 +10,6 @@ #include <memory> #include <string> -#include "ash/wm/lock_state_observer.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" @@ -45,7 +44,6 @@ // Displays a WebUI lock screen based on the Oobe account picker screen. class WebUIScreenLocker : public WebUILoginView, public LoginDisplay::Delegate, - public ash::LockStateObserver, public views::WidgetObserver, public PowerManagerClient::Observer, public display::DisplayObserver, @@ -88,6 +86,9 @@ // Called when the webui header bar becomes visible. void OnHeaderBarVisible(); + // Called by ScreenLocker to notify that ash lock animation finishes. + void OnLockAnimationFinished(); + private: friend class test::WebUIScreenLockerTester; @@ -119,9 +120,6 @@ void Signout() override; bool IsUserWhitelisted(const AccountId& account_id) override; - // LockStateObserver: - void OnLockStateEvent(ash::LockStateObserver::EventType event) override; - // WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override;
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index 844c92e..0f2380d 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1724,13 +1724,7 @@ } // Tests that toolbox window is loaded when DevTools window is undocked. -// Crashes on Linux only. https://crbug.com/702641 -#if defined(OS_LINUX) -#define MAYBE_TestToolboxLoadedUndocked DISABLED_TestToolboxLoadedUndocked -#else -#define MAYBE_TestToolboxLoadedUndocked TestToolboxLoadedUndocked -#endif -IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestToolboxLoadedUndocked) { +IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestToolboxLoadedUndocked) { OpenDevToolsWindow(kDebuggerTestPage, false); ASSERT_TRUE(toolbox_web_contents()); DevToolsWindow* on_self =
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index ef9f2557..a9ccfbb 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -621,8 +621,17 @@ chrome::NavigateParams navigate_params(new_window, url, ui::PAGE_TRANSITION_LINK); navigate_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; + + // The next 2 statements put the new contents in the same BrowsingInstance + // as their opener. Note that |force_new_process_for_new_contents = false| + // means that new contents might still end up in a new renderer + // (if they open a web URL and are transferred out of an extension + // renderer), but even in this case the flags below ensure findability via + // window.open. + navigate_params.force_new_process_for_new_contents = false; navigate_params.source_site_instance = render_frame_host()->GetSiteInstance(); + chrome::Navigate(&navigate_params); }
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc index 17bc023..e0afb588 100644 --- a/chrome/browser/extensions/api/tabs/tabs_test.cc +++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -39,6 +39,7 @@ #include "components/prefs/pref_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/page_zoom.h" #include "content/public/common/url_constants.h" @@ -2116,7 +2117,7 @@ } // Regression test for crbug.com/660498. -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Foo) { +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TemporaryAddressSpoof) { ASSERT_TRUE(StartEmbeddedTestServer()); content::WebContents* first_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -2144,4 +2145,45 @@ EXPECT_EQ(url, second_web_contents->GetVisibleURL()); } +// Window created by chrome.windows.create should be in the same SiteInstance +// and BrowsingInstance as the opener - this is a regression test for +// hangouts-vs-isolate-extensions-trouble (see also https://crbug.com/597750). +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowsCreateVsSiteInstance) { + const extensions::Extension* extension = + LoadExtension(test_data_dir_.AppendASCII("../simple_with_file")); + ASSERT_TRUE(extension); + + // Navigate a tab to an extension page. + GURL extension_url = extension->GetResourceURL("file.html"); + ui_test_utils::NavigateToURL(browser(), extension_url); + content::WebContents* old_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // Execute chrome.windows.create and store the new tab in |new_contents|. + content::WebContents* new_contents = nullptr; + { + content::WebContentsAddedObserver observer; + ASSERT_TRUE(content::ExecuteScript(old_contents, + "window.name = 'test-name';\n" + "chrome.windows.create({url: '" + + extension_url.spec() + "'})")); + new_contents = observer.GetWebContents(); + } + + // Verify that the old and new tab are in the same process and SiteInstance. + // Note: both test assertions are important - one observed failure mode was + // having the same process, but different SiteInstance. + EXPECT_EQ(old_contents->GetMainFrame()->GetProcess(), + new_contents->GetMainFrame()->GetProcess()); + EXPECT_EQ(old_contents->GetMainFrame()->GetSiteInstance(), + new_contents->GetMainFrame()->GetSiteInstance()); + + // Verify that the |new_contents| doesn't have a |window.opener| set. + bool window_opener_cast_to_bool = true; + EXPECT_TRUE(ExecuteScriptAndExtractBool( + new_contents, "window.domAutomationController.send(!!window.opener)", + &window_opener_cast_to_bool)); + EXPECT_FALSE(window_opener_cast_to_bool); +} + } // namespace extensions
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index d1ba3ed..f20bc0b 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1209,11 +1209,10 @@ #if defined(OS_ANDROID) const char kEnableDataReductionProxyMainMenuName[] = - "Enable Data Saver main menu item"; + "Enable Data Saver main menu footer"; const char kEnableDataReductionProxyMainMenuDescription[] = - "Enables the Data Saver menu item in the main menu rather than under " - "Settings."; + "Enables the Data Saver footer in the main menu"; const char kEnableDataReductionProxySiteBreakdownName[] = "Data Saver Site Breakdown";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 41117360..3e28987 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1339,12 +1339,11 @@ #if defined(OS_ANDROID) -// An about:flags experiment title to enable the Data Saver menu item in the -// main menu rather than under settings on Android +// An about:flags experiment title to enable the Data Saver footer on Android extern const char kEnableDataReductionProxyMainMenuName[]; -// Describes an about:flags experiment to enable the Data Saver menu item in the -// main menu rather than under settings on Android +// Describes an about:flags experiment to enable the Data Saver footer in the +// main menu on Android extern const char kEnableDataReductionProxyMainMenuDescription[]; // An about:flags experiment title to enable the site breakdown on the Data
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc index c7df704..2a8db3e 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc +++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -357,13 +357,29 @@ void MediaStreamDevicesController::PromptAnswered(ContentSetting setting, bool persist) { - ContentSetting audio_setting = GetNewSetting( - CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, old_audio_setting_, setting); - ContentSetting video_setting = GetNewSetting( - CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, old_video_setting_, setting); + DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (persist) - StorePermission(audio_setting, video_setting); + HostContentSettingsMap* host_content_settings_map = + HostContentSettingsMapFactory::GetForProfile(profile_); + ContentSetting audio_setting = old_audio_setting_; + if (old_audio_setting_ == CONTENT_SETTING_ASK) { + if (persist && setting != CONTENT_SETTING_ASK) { + host_content_settings_map->SetContentSettingDefaultScope( + request_.security_origin, GURL(), + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting); + } + audio_setting = setting; + } + + ContentSetting video_setting = old_video_setting_; + if (old_video_setting_ == CONTENT_SETTING_ASK) { + if (persist && setting != CONTENT_SETTING_ASK) { + host_content_settings_map->SetContentSettingDefaultScope( + request_.security_origin, GURL(), + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting); + } + video_setting = setting; + } content::MediaStreamRequestResult denial_reason = content::MEDIA_DEVICE_OK; if (setting == CONTENT_SETTING_ASK) @@ -455,6 +471,9 @@ const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) : web_contents_(web_contents), request_(request), callback_(callback) { + DCHECK(content::IsOriginSecure(request_.security_origin) || + request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); + profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); @@ -625,28 +644,6 @@ base::ResetAndReturn(&callback_).Run(devices, request_result, std::move(ui)); } -void MediaStreamDevicesController::StorePermission( - ContentSetting new_audio_setting, - ContentSetting new_video_setting) const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(content::IsOriginSecure(request_.security_origin) || - request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); - - if (IsAskingForAudio() && new_audio_setting != CONTENT_SETTING_ASK) { - HostContentSettingsMapFactory::GetForProfile(profile_) - ->SetContentSettingDefaultScope(request_.security_origin, GURL(), - CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, - std::string(), new_audio_setting); - } - if (IsAskingForVideo() && new_video_setting != CONTENT_SETTING_ASK) { - HostContentSettingsMapFactory::GetForProfile(profile_) - ->SetContentSettingDefaultScope( - request_.security_origin, GURL(), - CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), - new_video_setting); - } -} - void MediaStreamDevicesController::UpdateTabSpecificContentSettings( ContentSetting audio_setting, ContentSetting video_setting) const { @@ -735,16 +732,6 @@ return result.content_setting; } -ContentSetting MediaStreamDevicesController::GetNewSetting( - ContentSettingsType content_type, - ContentSetting old_setting, - ContentSetting user_decision) const { - ContentSetting result = old_setting; - if (old_setting == CONTENT_SETTING_ASK) - result = user_decision; - return result; -} - bool MediaStreamDevicesController::IsUserAcceptAllowed( ContentSettingsType content_type) const { #if defined(OS_ANDROID)
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.h b/chrome/browser/media/webrtc/media_stream_devices_controller.h index bcf5ce0..4b8dd59 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller.h +++ b/chrome/browser/media/webrtc/media_stream_devices_controller.h
@@ -145,11 +145,6 @@ ContentSetting video_setting, content::MediaStreamRequestResult denial_reason); - // Store the permission to use media devices for the origin of the request. - // This is triggered when the user makes a decision. - void StorePermission(ContentSetting new_audio_setting, - ContentSetting new_video_setting) const; - // Called when the permission has been set to update the // TabSpecificContentSettings. void UpdateTabSpecificContentSettings(ContentSetting audio_setting, @@ -161,14 +156,6 @@ const content::MediaStreamRequest& request, content::MediaStreamRequestResult* denial_reason) const; - // Returns the content setting that should apply given an old content setting - // and a user decision that has been made. If a user isn't being asked for one - // of audio/video then we shouldn't change that setting, even if they accept - // the dialog. - ContentSetting GetNewSetting(ContentSettingsType content_type, - ContentSetting old_setting, - ContentSetting user_decision) const; - // Returns true if clicking allow on the dialog should give access to the // requested devices. bool IsUserAcceptAllowed(ContentSettingsType content_type) const;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index d3e6e4b..f2a9a285 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -82,6 +82,7 @@ #include "net/base/load_flags.h" #include "net/base/network_change_notifier.h" #include "net/base/port_util.h" +#include "net/dns/mock_host_resolver.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_fetcher.h" @@ -761,28 +762,18 @@ clients_.clear(); } -void SyncTest::SetUpInProcessBrowserTestFixture() { - // We don't take a reference to |resolver|, but mock_host_resolver_override_ - // does, so effectively assumes ownership. - net::RuleBasedHostResolverProc* resolver = - new net::RuleBasedHostResolverProc(host_resolver()); - resolver->AllowDirectLookup("*.google.com"); +void SyncTest::SetUpOnMainThread() { + host_resolver()->AllowDirectLookup("*.google.com"); // Allow connection to googleapis.com for oauth token requests in E2E tests. - resolver->AllowDirectLookup("*.googleapis.com"); + host_resolver()->AllowDirectLookup("*.googleapis.com"); // On Linux, we use Chromium's NSS implementation which uses the following // hosts for certificate verification. Without these overrides, running the // integration tests on Linux causes error as we make external DNS lookups. - resolver->AllowDirectLookup("*.thawte.com"); - resolver->AllowDirectLookup("*.geotrust.com"); - resolver->AllowDirectLookup("*.gstatic.com"); - mock_host_resolver_override_ = - base::MakeUnique<net::ScopedDefaultHostResolverProc>(resolver); -} - -void SyncTest::TearDownInProcessBrowserTestFixture() { - mock_host_resolver_override_.reset(); + host_resolver()->AllowDirectLookup("*.thawte.com"); + host_resolver()->AllowDirectLookup("*.geotrust.com"); + host_resolver()->AllowDirectLookup("*.gstatic.com"); } void SyncTest::WaitForDataModels(Profile* profile) {
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index ba2b818..313ccd37 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -18,7 +18,6 @@ #include "components/sync/protocol/sync_protocol_error.h" #include "components/sync/test/fake_server/fake_server.h" #include "components/sync/test/local_sync_test_server.h" -#include "net/dns/mock_host_resolver.h" #include "net/http/http_status_code.h" #include "net/url_request/url_request_status.h" @@ -62,7 +61,6 @@ namespace net { class FakeURLFetcherFactory; -class ScopedDefaultHostResolverProc; class URLFetcherImplFactory; } // namespace net @@ -264,18 +262,10 @@ // on by default yet. virtual void AddOptionalTypesToCommandLine(base::CommandLine* cl); - // BrowserTestBase override. Destroys all the sync clients and sync - // profiles created by a test. + // BrowserTestBase implementation: + void SetUpOnMainThread() override; void TearDownOnMainThread() override; - // InProcessBrowserTest override. Changes behavior of the default host - // resolver to avoid DNS lookup errors. - void SetUpInProcessBrowserTestFixture() override; - - // InProcessBrowserTest override. Resets the host resolver its default - // behavior. - void TearDownInProcessBrowserTestFixture() override; - // Implementations of the EnableNotifications() and DisableNotifications() // functions defined above. void DisableNotificationsImpl(); @@ -456,12 +446,6 @@ // creation via http requests. bool create_gaia_account_at_runtime_; - // Sync integration tests need to make live DNS requests for access to - // GAIA and sync server URLs under google.com. We use a scoped version - // to override the default resolver while the test is active. - std::unique_ptr<net::ScopedDefaultHostResolverProc> - mock_host_resolver_override_; - // Used to start and stop the local test server. base::Process test_server_;
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.cc b/chrome/browser/ui/ash/palette_delegate_chromeos.cc index b9a52a7..cfa9553 100644 --- a/chrome/browser/ui/ash/palette_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/palette_delegate_chromeos.cc
@@ -179,8 +179,7 @@ auto* screenshot_controller = ash::Shell::Get()->screenshot_controller(); ash::ScreenshotDelegate* screenshot_delegate; - if (arc::ArcVoiceInteractionFrameworkService::IsVoiceInteractionEnabled() && - arc::IsArcAllowedForProfile(profile_)) { + if (IsMetalayerSupported()) { // This is an experimental mode. It will be either taken out or grow // into a separate tool next to "Capture region". if (!voice_interaction_screenshot_delegate_) { @@ -206,4 +205,35 @@ ash::Shell::Get()->screenshot_controller()->CancelScreenshotSession(); } +bool PaletteDelegateChromeOS::IsMetalayerSupported() { + if (!arc::IsArcAllowedForProfile(profile_)) + return false; + + arc::ArcVoiceInteractionFrameworkService* service = + arc::ArcServiceManager::Get() + ->GetService<arc::ArcVoiceInteractionFrameworkService>(); + return service && service->IsMetalayerSupported(); +} + +void PaletteDelegateChromeOS::ShowMetalayer(const base::Closure& closed) { + arc::ArcVoiceInteractionFrameworkService* service = + arc::ArcServiceManager::Get() + ->GetService<arc::ArcVoiceInteractionFrameworkService>(); + if (!service) { + if (!closed.is_null()) + closed.Run(); + return; + } + service->ShowMetalayer(closed); +} + +void PaletteDelegateChromeOS::HideMetalayer() { + arc::ArcVoiceInteractionFrameworkService* service = + arc::ArcServiceManager::Get() + ->GetService<arc::ArcVoiceInteractionFrameworkService>(); + if (!service) + return; + service->HideMetalayer(); +} + } // namespace chromeos
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.h b/chrome/browser/ui/ash/palette_delegate_chromeos.h index ac059a8..f303e51 100644 --- a/chrome/browser/ui/ash/palette_delegate_chromeos.h +++ b/chrome/browser/ui/ash/palette_delegate_chromeos.h
@@ -45,6 +45,9 @@ void TakeScreenshot() override; void TakePartialScreenshot(const base::Closure& done) override; void CancelPartialScreenshot() override; + bool IsMetalayerSupported() override; + void ShowMetalayer(const base::Closure& closed) override; + void HideMetalayer() override; // user_manager::UserManager::UserSessionStateObserver: void ActiveUserChanged(const user_manager::User* active_user) override;
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc index 3325fa21..693ad99 100644 --- a/chrome/browser/ui/ash/session_controller_client.cc +++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -118,6 +118,10 @@ return g_instance; } +void SessionControllerClient::StartLock(StartLockCallback callback) { + session_controller_->StartLock(callback); +} + void SessionControllerClient::RunUnlockAnimation( base::Closure animation_finished_callback) { session_controller_->RunUnlockAnimation(animation_finished_callback);
diff --git a/chrome/browser/ui/ash/session_controller_client.h b/chrome/browser/ui/ash/session_controller_client.h index ab9ba3f9..bad771a1 100644 --- a/chrome/browser/ui/ash/session_controller_client.h +++ b/chrome/browser/ui/ash/session_controller_client.h
@@ -37,6 +37,13 @@ static SessionControllerClient* Get(); + // Calls SessionController to start locking ash. |callback| will be invoked + // to indicate whether the lock is successful. If |locked| is true, the post + // lock animation is finished and ash is fully locked. Otherwise, the lock + // is failed somehow. + using StartLockCallback = base::Callback<void(bool locked)>; + void StartLock(StartLockCallback callback); + // Calls ash SessionController to run unlock animation. // |animation_finished_callback| will be invoked when the animation finishes. void RunUnlockAnimation(base::Closure animation_finished_callback);
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc index 1a7e806..e8190f6 100644 --- a/chrome/browser/ui/browser_navigator.cc +++ b/chrome/browser/ui/browser_navigator.cc
@@ -356,7 +356,7 @@ const GURL& url) { WebContents::CreateParams create_params( params.browser->profile(), - params.source_site_instance + params.source_site_instance && !params.force_new_process_for_new_contents ? params.source_site_instance : tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url)); create_params.main_frame_name = params.frame_name;
diff --git a/chrome/browser/ui/browser_navigator_params.cc b/chrome/browser/ui/browser_navigator_params.cc index 49b860b..c4a6264 100644 --- a/chrome/browser/ui/browser_navigator_params.cc +++ b/chrome/browser/ui/browser_navigator_params.cc
@@ -26,6 +26,7 @@ target_contents(a_target_contents), source_contents(nullptr), disposition(WindowOpenDisposition::CURRENT_TAB), + force_new_process_for_new_contents(false), trusted_source(false), transition(ui::PAGE_TRANSITION_LINK), is_renderer_initiated(false), @@ -49,6 +50,7 @@ target_contents(NULL), source_contents(NULL), disposition(WindowOpenDisposition::CURRENT_TAB), + force_new_process_for_new_contents(false), trusted_source(false), transition(a_transition), is_renderer_initiated(false), @@ -71,6 +73,7 @@ target_contents(a_target_contents), source_contents(NULL), disposition(WindowOpenDisposition::CURRENT_TAB), + force_new_process_for_new_contents(false), trusted_source(false), transition(ui::PAGE_TRANSITION_LINK), is_renderer_initiated(false), @@ -96,6 +99,7 @@ target_contents(NULL), source_contents(NULL), disposition(WindowOpenDisposition::NEW_FOREGROUND_TAB), + force_new_process_for_new_contents(false), trusted_source(false), transition(a_transition), is_renderer_initiated(false), @@ -126,6 +130,8 @@ nav_params->redirect_chain = params.redirect_chain; nav_params->extra_headers = params.extra_headers; nav_params->disposition = params.disposition; + nav_params->force_new_process_for_new_contents = + params.force_new_process_for_new_contents; nav_params->trusted_source = false; nav_params->is_renderer_initiated = params.is_renderer_initiated; nav_params->should_replace_current_entry =
diff --git a/chrome/browser/ui/browser_navigator_params.h b/chrome/browser/ui/browser_navigator_params.h index bf40e67..10778a1b 100644 --- a/chrome/browser/ui/browser_navigator_params.h +++ b/chrome/browser/ui/browser_navigator_params.h
@@ -132,6 +132,12 @@ // |tabstrip_add_types|. WindowOpenDisposition disposition; + // Controls creation of new web contents (in case |disposition| asks for a new + // tab or window). If |force_new_process_for_new_contents| is true, then we + // try to put the new contents in a new renderer, even if they are same-site + // as |source_site_instance| (this is subject to renderer process limits). + bool force_new_process_for_new_contents; + // Sets browser->is_trusted_source. Default is false. bool trusted_source;
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm index a840011..d884dd1 100644 --- a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm +++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
@@ -6,6 +6,7 @@ #include <memory> +#include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" #import "base/mac/scoped_nsobject.h" #import "base/mac/sdk_forward_declarations.h" @@ -53,16 +54,15 @@ }; // The touch bar's identifier. -const NSTouchBarCustomizationIdentifier kBrowserWindowTouchBarId = - @"BrowserWindowTouchBarId"; +NSString* const kBrowserWindowTouchBarId = @"browser-window"; // Touch bar items identifiers. -const NSTouchBarItemIdentifier kBackForwardTouchId = @"BackForwardTouchId"; -const NSTouchBarItemIdentifier kReloadOrStopTouchId = @"ReloadOrStopTouchId"; -const NSTouchBarItemIdentifier kHomeTouchId = @"HomeTouchId"; -const NSTouchBarItemIdentifier kSearchTouchId = @"SearchTouchId"; -const NSTouchBarItemIdentifier kStarTouchId = @"StarTouchId"; -const NSTouchBarItemIdentifier kNewTabTouchId = @"NewTabTouchId"; +NSString* const kBackForwardTouchId = @"BACK-FWD"; +NSString* const kReloadOrStopTouchId = @"RELOAD-STOP"; +NSString* const kHomeTouchId = @"HOME"; +NSString* const kSearchTouchId = @"SEARCH"; +NSString* const kStarTouchId = @"BOOKMARK"; +NSString* const kNewTabTouchId = @"NEW-TAB"; // The button indexes in the back and forward segment control. const int kBackSegmentIndex = 0; @@ -75,9 +75,8 @@ // The size of the touch bar icons. const int kTouchBarIconSize = 16; -// The width of the search button in the touch bar. -const int kSearchBtnWidthWithHomeBtn = 205; -const int kSearchBtnWidthWithoutHomeBtn = 280; +// The min width of the search button in the touch bar. +const int kSearchBtnMinWidth = 205; // Creates an NSImage from the given VectorIcon. NSImage* CreateNSImageFromIcon(const gfx::VectorIcon& icon, @@ -102,6 +101,18 @@ return button; } +NSString* GetTouchBarId(NSString* const touch_bar_id) { + 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]; +} + TouchBarAction TouchBarActionFromCommand(int command) { switch (command) { case IDC_BACK: @@ -205,22 +216,29 @@ base::scoped_nsobject<NSTouchBar> touchBar( [[NSClassFromString(@"NSTouchBar") alloc] init]); - NSArray* touchBarItemIdentifiers; - if (showHomeButton_.GetValue()) { - touchBarItemIdentifiers = @[ - kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId, - kStarTouchId, kNewTabTouchId - ]; - } else { - touchBarItemIdentifiers = @[ - kBackForwardTouchId, kReloadOrStopTouchId, kSearchTouchId, kStarTouchId, - kNewTabTouchId - ]; + NSMutableArray* customIdentifiers = [NSMutableArray arrayWithCapacity:7]; + NSMutableArray* defaultIdentifiers = [NSMutableArray arrayWithCapacity:6]; + + NSArray* touchBarItems = @[ + kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId, + kStarTouchId, kNewTabTouchId + ]; + + for (NSString* item in touchBarItems) { + NSString* itemIdentifier = + GetTouchBarItemId(kBrowserWindowTouchBarId, item); + [customIdentifiers addObject:itemIdentifier]; + + // Don't add the home button if it's not shown in the toolbar. + if (showHomeButton_.GetValue() || ![item isEqualTo:kHomeTouchId]) + [defaultIdentifiers addObject:itemIdentifier]; } - [touchBar setCustomizationIdentifier:kBrowserWindowTouchBarId]; - [touchBar setDefaultItemIdentifiers:touchBarItemIdentifiers]; - [touchBar setCustomizationAllowedItemIdentifiers:touchBarItemIdentifiers]; + [customIdentifiers addObject:NSTouchBarItemIdentifierFlexibleSpace]; + + [touchBar setCustomizationIdentifier:GetTouchBarId(kBrowserWindowTouchBarId)]; + [touchBar setDefaultItemIdentifiers:defaultIdentifiers]; + [touchBar setCustomizationAllowedItemIdentifiers:customIdentifiers]; [touchBar setDelegate:self]; return touchBar.autorelease(); @@ -233,23 +251,35 @@ base::scoped_nsobject<NSCustomTouchBarItem> touchBarItem([[NSClassFromString( @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]); - if ([identifier isEqualTo:kBackForwardTouchId]) { + if ([identifier hasSuffix:kBackForwardTouchId]) { [touchBarItem setView:[self backOrForwardTouchBarView]]; - } else if ([identifier isEqualTo:kReloadOrStopTouchId]) { + [touchBarItem setCustomizationLabel: + l10n_util::GetNSString( + IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL)]; + } else if ([identifier hasSuffix:kReloadOrStopTouchId]) { const gfx::VectorIcon& icon = isPageLoading_ ? kNavigateStopIcon : kNavigateReloadIcon; int commandId = isPageLoading_ ? IDC_STOP : IDC_RELOAD; int tooltipId = isPageLoading_ ? IDS_TOOLTIP_STOP : IDS_TOOLTIP_RELOAD; [touchBarItem setView:CreateTouchBarButton(icon, self, commandId, tooltipId)]; - } else if ([identifier isEqualTo:kHomeTouchId]) { + [touchBarItem setCustomizationLabel: + l10n_util::GetNSString( + IDS_TOUCH_BAR_STOP_RELOAD_CUSTOMIZATION_LABEL)]; + } else if ([identifier hasSuffix:kHomeTouchId]) { [touchBarItem setView:CreateTouchBarButton(kNavigateHomeIcon, self, IDC_HOME, IDS_TOOLTIP_HOME)]; - } else if ([identifier isEqualTo:kNewTabTouchId]) { + [touchBarItem + setCustomizationLabel:l10n_util::GetNSString( + IDS_TOUCH_BAR_HOME_CUSTOMIZATION_LABEL)]; + } else if ([identifier hasSuffix:kNewTabTouchId]) { [touchBarItem setView:CreateTouchBarButton(kNewTabMacTouchbarIcon, self, IDC_NEW_TAB, IDS_TOOLTIP_NEW_TAB)]; - } else if ([identifier isEqualTo:kStarTouchId]) { + [touchBarItem + setCustomizationLabel:l10n_util::GetNSString( + IDS_TOUCH_BAR_NEW_TAB_CUSTOMIZATION_LABEL)]; + } else if ([identifier hasSuffix:kStarTouchId]) { const gfx::VectorIcon& icon = isStarred_ ? toolbar::kStarActiveIcon : toolbar::kStarIcon; SkColor iconColor = @@ -257,8 +287,13 @@ int tooltipId = isStarred_ ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR; [touchBarItem setView:CreateTouchBarButton(icon, self, IDC_BOOKMARK_PAGE, tooltipId, iconColor)]; - } else if ([identifier isEqualTo:kSearchTouchId]) { + [touchBarItem + setCustomizationLabel:l10n_util::GetNSString( + IDS_TOUCH_BAR_BOOKMARK_CUSTOMIZATION_LABEL)]; + } else if ([identifier hasSuffix:kSearchTouchId]) { [touchBarItem setView:[self searchTouchBarView]]; + [touchBarItem setCustomizationLabel:l10n_util::GetNSString( + IDS_TOUCH_BAR_GOOGLE_SEARCH)]; } return touchBarItem.autorelease(); @@ -329,9 +364,12 @@ action:@selector(executeCommand:)]; searchButton.imageHugsTitle = YES; searchButton.tag = IDC_FOCUS_LOCATION; - int width = showHomeButton_.GetValue() ? kSearchBtnWidthWithHomeBtn - : kSearchBtnWidthWithoutHomeBtn; - [searchButton.widthAnchor constraintEqualToConstant:width].active = YES; + [searchButton.widthAnchor + constraintGreaterThanOrEqualToConstant:kSearchBtnMinWidth] + .active = YES; + [searchButton + setContentHuggingPriority:1.0 + forOrientation:NSLayoutConstraintOrientationHorizontal]; return searchButton; }
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm index 11932109..339f2ebe 100644 --- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -409,8 +409,10 @@ NSWidth([closeButton frame]) + chrome_style::kCloseButtonPadding; - bubbleFrame.size.width = std::max( - NSWidth(bubbleFrame), std::max(titleRowWidth, maxPermissionLineWidth)); + bubbleFrame.size.width = + std::max(NSWidth(bubbleFrame), + std::max(titleRowWidth, maxPermissionLineWidth)) + + kHorizontalPadding; // Now that the bubble's dimensions have been set, lay out the buttons and // menus.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java index 248cbc47..e6f9f09 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
@@ -10,7 +10,6 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.UrlUtils; import org.chromium.base.test.util.parameter.BaseParameter; import org.chromium.base.test.util.parameter.Parameter; import org.chromium.base.test.util.parameter.Parameterizable; @@ -38,98 +37,8 @@ }) public abstract class MultiActivityTestBase extends InstrumentationTestCase implements Parameterizable { - protected static final String URL_1 = createTestUrl(1); - protected static final String URL_2 = createTestUrl(2); - protected static final String URL_3 = createTestUrl(3); - protected static final String URL_4 = createTestUrl(4); - private Parameter.Reader mParameterReader; private Map<String, BaseParameter> mAvailableParameters; - - /** Defines one gigantic link spanning the whole page that creates a new window with URL_4. */ - public static final String HREF_LINK = UrlUtils.encodeHtmlDataUri( - "<html>" - + " <head>" - + " <title>href link page</title>" - + " <meta name='viewport'" - + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" - + " <style>" - + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" - + " </style>" - + " </head>" - + " <body>" - + " <a href='" + URL_4 + "' target='_blank'><div></div></a>" - + " </body>" - + "</html>"); - - /** Same as HREF_LINK, but disallowing a referrer from being sent triggers another codepath. */ - protected static final String HREF_NO_REFERRER_LINK = UrlUtils.encodeHtmlDataUri( - "<html>" - + " <head>" - + " <title>href no referrer link page</title>" - + " <meta name='viewport'" - + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" - + " <style>" - + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" - + " </style>" - + " </head>" - + " <body>" - + " <a href='" + URL_4 + "' target='_blank' rel='noreferrer'><div></div></a>" - + " </body>" - + "</html>"); - - /** Clicking the body triggers a window.open() call to open URL_4. */ - protected static final String SUCCESS_URL = UrlUtils.encodeHtmlDataUri("opened!"); - protected static final String ONCLICK_LINK = UrlUtils.encodeHtmlDataUri( - "<html>" - + " <head>" - + " <title>window.open page</title>" - + " <meta name='viewport'" - + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" - + " <style>" - + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" - + " </style>" - + " <script>" - + " function openNewWindow() {" - + " var site = window.open('" + URL_4 + "');" - + " if (site) location.href = '" + SUCCESS_URL + "';" - + " }" - + " </script>" - + " </head>" - + " <body id='body'>" - + " <div onclick='openNewWindow()'></div>" - + " </body>" - + "</html>"); - - /** Opens a new page via window.open(), but get rid of the opener. */ - protected static final String ONCLICK_NO_REFERRER_LINK = UrlUtils.encodeHtmlDataUri( - "<html>" - + " <head>" - + " <title>window.open page, opener set to null</title>" - + " <meta name='viewport'" - + " content='width=device-width initial-scale=0.5, maximum-scale=0.5'>" - + " <style>" - + " body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}" - + " </style>" - + " <script>" - + " function openWithoutReferrer() {" - + " var site = window.open();" - + " site.opener = null;" - + " site.document.open();" - + " site.document.write(" - + " '<meta http-equiv=\"refresh\" content=\"0;url=" + URL_4 + "\">');" - + " site.document.close();" - + " if (site) location.href = '" + SUCCESS_URL + "';" - + " }" - + " </script>" - + " </head>" - + " <body>" - + " <a onclick='openWithoutReferrer()'>" - + " <div>The bug that just keeps on coming back.</div>" - + " </a>" - + " </body>" - + "</html>"); - protected MockStorageDelegate mStorageDelegate; protected Context mContext; @@ -243,17 +152,4 @@ protected Parameter.Reader getParameterReader() { return mParameterReader; } - - private static final String createTestUrl(int index) { - String[] colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#ffff00"}; - return UrlUtils.encodeHtmlDataUri( - "<html>" - + " <head>" - + " <title>Page " + index + "</title>" - + " <meta name='viewport' content='width=device-width " - + " initial-scale=0.5 maximum-scale=0.5'>" - + " </head>" - + " <body style='margin: 0em; background: " + colors[index] + ";'></body>" - + "</html>"); - } }
diff --git a/chrome/test/data/frame_tree/anchor_to_same_site_location.html b/chrome/test/data/frame_tree/anchor_to_same_site_location.html new file mode 100644 index 0000000..56ce8037 --- /dev/null +++ b/chrome/test/data/frame_tree/anchor_to_same_site_location.html
@@ -0,0 +1,22 @@ +<!doctype html> +<html> +<head> +<script> +window.name = "main_contents"; +function simulateClick(anchor_name, properties) { + var evt = new MouseEvent("click", properties); + + target = document.getElementById(anchor_name); + return target.dispatchEvent(evt); +} +</script> +</head> +<body> +This page helps testing shift-clicking or ctrl-clicking an anchor/link +that points to the same site. See also https://crbug.com/23815 and/or +https://crbug.com/658386. +<hr> +<a href="/title1.html" + id="test-anchor-no-target">Test link to click while holding ctrl key</a> +</body> +</html>
diff --git a/chrome/test/data/payments/payment_request_shipping_address_change_test.html b/chrome/test/data/payments/payment_request_shipping_address_change_test.html new file mode 100644 index 0000000..c366e4b --- /dev/null +++ b/chrome/test/data/payments/payment_request_shipping_address_change_test.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<head> +<title>Shipping Address Change Test</title> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> +<link rel="stylesheet" type="text/css" href="style.css"> +</head> +<body> +<button onclick="buy()" id="buy">Shipping Address Change Test</button> +<pre id="result"></pre> +<script src="util.js"></script> +<script src="shipping_address_change.js"></script> +</body> +</html>
diff --git a/chrome/test/data/payments/shipping_address_change.js b/chrome/test/data/payments/shipping_address_change.js new file mode 100644 index 0000000..8bff1ff --- /dev/null +++ b/chrome/test/data/payments/shipping_address_change.js
@@ -0,0 +1,44 @@ +/* + * 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. + */ + +/** + * Launches the PaymentRequest UI that prints the shipping address received + * on shippingAddressChange events at the end of the transaction. + */ +function buy() { // eslint-disable-line no-unused-vars + try { + var details = { + total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}, + displayItems: [ + { + label: 'Pending shipping price', + amount: {currency: 'USD', value: '0.00'}, + pending: true + }, + { + label: 'Subtotal', + amount: {currency: 'USD', value: '5.00'} + } + ] + }; + + var request = new PaymentRequest( + [{supportedMethods: ['visa']}], details, {requestShipping: true}); + + var shippingAddressChange; + + request.addEventListener('shippingaddresschange', function(evt) { + evt.updateWith(new Promise(function(resolve) { + print(JSON.stringify(request.shippingAddress, undefined, 2)); + resolve(details); + })); + }); + + request.show(); + } catch (error) { + print(error.message); + } +}
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn index e5bc418..e4ba616 100644 --- a/chromeos/components/tether/BUILD.gn +++ b/chromeos/components/tether/BUILD.gn
@@ -49,6 +49,8 @@ "pref_names.h", "tether_connector.cc", "tether_connector.h", + "tether_device_state_manager.cc", + "tether_device_state_manager.h", "tether_host_fetcher.cc", "tether_host_fetcher.h", "tether_network_disconnection_handler.cc",
diff --git a/chromeos/components/tether/active_host_network_state_updater_unittest.cc b/chromeos/components/tether/active_host_network_state_updater_unittest.cc index 2acf577..57e95e5 100644 --- a/chromeos/components/tether/active_host_network_state_updater_unittest.cc +++ b/chromeos/components/tether/active_host_network_state_updater_unittest.cc
@@ -47,6 +47,8 @@ void SetUp() override { DBusThreadManager::Initialize(); NetworkStateTest::SetUp(); + network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); SetUpTetherNetwork(); SetUpWifiNetwork();
diff --git a/chromeos/components/tether/host_scanner_unittest.cc b/chromeos/components/tether/host_scanner_unittest.cc index e59cb6b..1ca133fc 100644 --- a/chromeos/components/tether/host_scanner_unittest.cc +++ b/chromeos/components/tether/host_scanner_unittest.cc
@@ -139,6 +139,8 @@ void SetUp() override { DBusThreadManager::Initialize(); NetworkStateTest::SetUp(); + network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); scanned_device_infos_so_far_.clear();
diff --git a/chromeos/components/tether/initializer.cc b/chromeos/components/tether/initializer.cc index 0eafb693..78a5e42 100644 --- a/chromeos/components/tether/initializer.cc +++ b/chromeos/components/tether/initializer.cc
@@ -15,6 +15,7 @@ #include "chromeos/components/tether/local_device_data_provider.h" #include "chromeos/components/tether/notification_presenter.h" #include "chromeos/components/tether/tether_connector.h" +#include "chromeos/components/tether/tether_device_state_manager.h" #include "chromeos/components/tether/tether_host_fetcher.h" #include "chromeos/components/tether/wifi_hotspot_connector.h" #include "chromeos/network/network_connect.h" @@ -152,6 +153,8 @@ PA_LOG(INFO) << "Successfully set Bluetooth advertisement interval. " << "Initializing tether feature."; + tether_device_state_manager_ = + base::MakeUnique<TetherDeviceStateManager>(network_state_handler_); tether_host_fetcher_ = base::MakeUnique<TetherHostFetcher>(cryptauth_service_); local_device_data_provider_ =
diff --git a/chromeos/components/tether/initializer.h b/chromeos/components/tether/initializer.h index abb4e919..c633bebe 100644 --- a/chromeos/components/tether/initializer.h +++ b/chromeos/components/tether/initializer.h
@@ -39,6 +39,7 @@ class LocalDeviceDataProvider; class NotificationPresenter; class TetherConnector; +class TetherDeviceStateManager; class TetherHostFetcher; class WifiHotspotConnector; @@ -94,6 +95,7 @@ // Declare new objects in the order that they will be created during // initialization to ensure that they are destroyed in the correct order. This // order will be enforced by InitializerTest.TestCreateAndDestroy. + std::unique_ptr<TetherDeviceStateManager> tether_device_state_manager_; std::unique_ptr<TetherHostFetcher> tether_host_fetcher_; std::unique_ptr<LocalDeviceDataProvider> local_device_data_provider_; std::unique_ptr<cryptauth::RemoteBeaconSeedFetcher>
diff --git a/chromeos/components/tether/tether_connector_unittest.cc b/chromeos/components/tether/tether_connector_unittest.cc index 3384831..dc3ce92 100644 --- a/chromeos/components/tether/tether_connector_unittest.cc +++ b/chromeos/components/tether/tether_connector_unittest.cc
@@ -148,6 +148,8 @@ void SetUp() override { DBusThreadManager::Initialize(); NetworkStateTest::SetUp(); + network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); fake_operation_factory_ = base::WrapUnique(new FakeConnectTetheringOperationFactory());
diff --git a/chromeos/components/tether/tether_device_state_manager.cc b/chromeos/components/tether/tether_device_state_manager.cc new file mode 100644 index 0000000..a8c561e --- /dev/null +++ b/chromeos/components/tether/tether_device_state_manager.cc
@@ -0,0 +1,38 @@ +// 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 "chromeos/components/tether/tether_device_state_manager.h" + +#include "chromeos/network/network_state_handler.h" + +namespace chromeos { + +namespace tether { + +TetherDeviceStateManager::TetherDeviceStateManager( + NetworkStateHandler* network_state_handler) + : network_state_handler_(network_state_handler) { + network_state_handler_->AddObserver(this, FROM_HERE); + + // TODO(hansberry): Set the appropriate value. For now, always set ENABLED. + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); +} + +TetherDeviceStateManager::~TetherDeviceStateManager() { + network_state_handler_->RemoveObserver(this, FROM_HERE); + + // TODO(hansberry): Determine if this should be PROHIBITED or UNAVAILABLE + // based on reason for shutting down. + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE); +} + +void TetherDeviceStateManager::DeviceListChanged() { + // TODO(hansberry): Implement. +} + +} // namespace tether + +} // namespace chromeos
diff --git a/chromeos/components/tether/tether_device_state_manager.h b/chromeos/components/tether/tether_device_state_manager.h new file mode 100644 index 0000000..4f05e70 --- /dev/null +++ b/chromeos/components/tether/tether_device_state_manager.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 CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_ +#define CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_ + +#include "base/macros.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_state_handler_observer.h" + +namespace chromeos { + +class NetworkStateHandler; + +namespace tether { + +// Manages the device state of tether networks. The tether state is: +// *TECHNOLOGY_PROHIBITED when tethering is disallowed by policy. +// *TECHNOLOGY_UNAVAILABLE when tethering is allowed by policy, but either +// the device has no Bluetooth capabilities or the logged-in user has no +// tether hosts associated with their account. +// *TECHNOLOGY_AVAILABLE when tethering is allowed by policy, the device has +// Bluetooth capabilities, the logged-in user has tether hosts associated +// with their account, but the Instant Tethering setting is disabled. +// *TECHNOLOGY_ENABLED when tethering is allowed by policy, the device has +// Bluetooth capabilities, the logged-in user has tether hosts associated +// with their account, and the Instant Tethering setting is enabled. +// TODO(hansberry): Complete this class description when implemented. +class TetherDeviceStateManager : public NetworkStateHandlerObserver { + public: + explicit TetherDeviceStateManager(NetworkStateHandler* network_state_handler); + ~TetherDeviceStateManager() override; + + // NetworkStateHandlerObserver: + void DeviceListChanged() override; + + private: + NetworkStateHandler* network_state_handler_; + + DISALLOW_COPY_AND_ASSIGN(TetherDeviceStateManager); +}; + +} // namespace tether + +} // namespace chromeos + +#endif // CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_
diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h index 97ebd0b9..59bd3d82 100644 --- a/chromeos/network/device_state.h +++ b/chromeos/network/device_state.h
@@ -35,6 +35,7 @@ // Accessors const std::string& mac_address() const { return mac_address_; } bool scanning() const { return scanning_; } + void set_scanning(bool scanning) { scanning_ = scanning; } // Cellular specific accessors const std::string& home_provider_id() const { return home_provider_id_; }
diff --git a/chromeos/network/managed_state.h b/chromeos/network/managed_state.h index 1fe17c8..9573af708 100644 --- a/chromeos/network/managed_state.h +++ b/chromeos/network/managed_state.h
@@ -112,6 +112,7 @@ private: friend class NetworkChangeNotifierChromeosUpdateTest; + friend class NetworkStateHandler; ManagedType managed_type_;
diff --git a/chromeos/network/network_connect_unittest.cc b/chromeos/network/network_connect_unittest.cc index 930b3d0..2eb4d44 100644 --- a/chromeos/network/network_connect_unittest.cc +++ b/chromeos/network/network_connect_unittest.cc
@@ -336,6 +336,9 @@ TEST_F(NetworkConnectTest, ConnectToTetherNetwork) { EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(kTether1Guid)); + NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + NetworkHandler::Get()->network_state_handler()->AddTetherNetworkState( kTether1Guid, "TetherNetwork", "Carrier", 100 /* battery_percentage */, 100 /* signal_strength */); @@ -347,6 +350,9 @@ TEST_F(NetworkConnectTest, ConnectToTetherNetwork_TetherNetworkDoesNotExist) { EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(_)).Times(0); + NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + NetworkConnect::Get()->SetTetherDelegate(mock_tether_delegate_.get()); NetworkConnect::Get()->ConnectToNetworkId(kTether1Guid); } @@ -354,6 +360,9 @@ TEST_F(NetworkConnectTest, ConnectToTetherNetwork_TetherDelegateNotSet) { EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(_)).Times(0); + NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + NetworkHandler::Get()->network_state_handler()->AddTetherNetworkState( kTether1Guid, "TetherNetwork", "Carrier", 100 /* battery_percentage */, 100 /* signal_strength */);
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc index 81d3492..7f372d7 100644 --- a/chromeos/network/network_connection_handler.cc +++ b/chromeos/network/network_connection_handler.cc
@@ -118,6 +118,8 @@ const char NetworkConnectionHandler::kErrorUnmanagedNetwork[] = "unmanaged-network"; const char NetworkConnectionHandler::kErrorActivateFailed[] = "activate-failed"; +const char NetworkConnectionHandler::kEnabledOrDisabledWhenNotAvailable[] = + "not-available"; struct NetworkConnectionHandler::ConnectRequest { ConnectRequest(const std::string& service_path,
diff --git a/chromeos/network/network_connection_handler.h b/chromeos/network/network_connection_handler.h index af76d47f..e7e86d47 100644 --- a/chromeos/network/network_connection_handler.h +++ b/chromeos/network/network_connection_handler.h
@@ -102,6 +102,9 @@ // Network activation failed. static const char kErrorActivateFailed[]; + // Network was enabled/disabled when it was not available. + static const char kEnabledOrDisabledWhenNotAvailable[]; + ~NetworkConnectionHandler() override; void AddObserver(NetworkConnectionObserver* observer);
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index 3268f9f..39ebed6 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -21,7 +21,9 @@ #include "base/values.h" #include "chromeos/chromeos_switches.h" #include "chromeos/network/device_state.h" +#include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_event_log.h" +#include "chromeos/network/network_handler_callbacks.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler_observer.h" #include "chromeos/network/tether_constants.h" @@ -126,9 +128,7 @@ std::string technology = GetTechnologyForType(type); if (technology == kTypeTether) { - bool is_tether_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnableTether); - return is_tether_enabled ? TECHNOLOGY_ENABLED : TECHNOLOGY_UNAVAILABLE; + return tether_technology_state_; } TechnologyState state; @@ -154,6 +154,25 @@ const network_handler::ErrorCallback& error_callback) { std::vector<std::string> technologies = GetTechnologiesForType(type); for (const std::string& technology : technologies) { + if (technology == kTypeTether) { + if (tether_technology_state_ != TECHNOLOGY_ENABLED && + tether_technology_state_ != TECHNOLOGY_AVAILABLE) { + NET_LOG(ERROR) << "SetTechnologyEnabled() called for the Tether " + << "DeviceState, but the current state was not " + << "TECHNOLOGY_ENABLED or TECHNOLOGY_AVAILABLE."; + network_handler::RunErrorCallback( + error_callback, kTetherDevicePath, + NetworkConnectionHandler::kEnabledOrDisabledWhenNotAvailable, ""); + continue; + } + + // Tether does not exist in Shill, so set |tether_technology_state_| and + // skip the below interactions with |shill_property_handler_|. + tether_technology_state_ = + enabled ? TECHNOLOGY_ENABLED : TECHNOLOGY_AVAILABLE; + continue; + } + if (!shill_property_handler_->IsTechnologyAvailable(technology)) continue; NET_LOG_USER("SetTechnologyEnabled", @@ -165,11 +184,54 @@ NotifyDeviceListChanged(); } +void NetworkStateHandler::SetTetherTechnologyState( + TechnologyState technology_state) { + if (tether_technology_state_ == technology_state) + return; + + tether_technology_state_ = technology_state; + EnsureTetherDeviceState(); + + // Signal Device/Technology state changed. + NotifyDeviceListChanged(); +} + +void NetworkStateHandler::SetTetherScanState(bool is_scanning) { + DeviceState* tether_device_state = + GetModifiableDeviceState(kTetherDevicePath); + DCHECK(tether_device_state); + + bool was_scanning = tether_device_state->scanning(); + tether_device_state->set_scanning(is_scanning); + + if (was_scanning && !is_scanning) { + // If a scan was in progress but has completed, notify observers. + NotifyScanCompleted(tether_device_state); + } +} + void NetworkStateHandler::SetProhibitedTechnologies( const std::vector<std::string>& prohibited_technologies, const network_handler::ErrorCallback& error_callback) { - shill_property_handler_->SetProhibitedTechnologies(prohibited_technologies, - error_callback); + // Make a copy of |prohibited_technologies| since the list may be edited + // within this function. + std::vector<std::string> prohibited_technologies_copy = + prohibited_technologies; + + for (auto it = prohibited_technologies_copy.begin(); + it < prohibited_technologies_copy.end(); ++it) { + if (*it == kTypeTether) { + // If Tether networks are prohibited, set |tether_technology_state_| and + // remove |kTypeTether| from the list before passing it to + // |shill_property_handler_| below. Shill does not have a concept of + // Tether networks, so it cannot prohibit that technology type. + tether_technology_state_ = TECHNOLOGY_PROHIBITED; + it = prohibited_technologies_copy.erase(it); + } + } + + shill_property_handler_->SetProhibitedTechnologies( + prohibited_technologies_copy, error_callback); // Signal Device/Technology state changed. NotifyDeviceListChanged(); } @@ -300,7 +362,7 @@ if (!network_list_sorted_) SortNetworkList(); // Sort to ensure visible networks are listed first. - // If |type| matches tether networks and at least one tether network is + // If |type| matches Tether networks and at least one Tether network is // present, return the first network (since it has been sorted already). if (type.MatchesPattern(NetworkTypePattern::Tether()) && !tether_network_list_.empty()) { @@ -323,9 +385,14 @@ std::string NetworkStateHandler::FormattedHardwareAddressForType( const NetworkTypePattern& type) const { const NetworkState* network = ConnectedNetworkByType(type); + if (network && network->type() == kTypeTether) { + // If this is a Tether network, get the MAC address corresponding to that + // network instead. + network = GetNetworkStateFromGuid(network->tether_guid()); + } const DeviceState* device = network ? GetDeviceState(network->device_path()) : GetDeviceStateByType(type); - if (!device) + if (!device || device->mac_address().empty()) return std::string(); return network_util::FormattedMacAddress(device->mac_address()); } @@ -361,7 +428,7 @@ if (type.Equals(NetworkTypePattern::Tether()) || (limit != 0 && count >= limit)) { - // If only searching for tether networks, there is no need to continue + // If only searching for Tether networks, there is no need to continue // searching through other network types; likewise, if the limit has already // been reached, there is no need to continue searching. return; @@ -432,6 +499,12 @@ DCHECK(battery_percentage >= 0 && battery_percentage <= 100); DCHECK(signal_strength >= 0 && signal_strength <= 100); + if (tether_technology_state_ != TECHNOLOGY_ENABLED) { + NET_LOG(ERROR) << "AddTetherNetworkState() called when Tether networks " + << "are not enabled. Cannot add NetworkState."; + return; + } + // If the network already exists, do nothing. if (GetNetworkStateFromGuid(guid)) { NET_LOG(ERROR) << "AddTetherNetworkState: " << name @@ -463,6 +536,12 @@ const std::string& carrier, int battery_percentage, int signal_strength) { + if (tether_technology_state_ != TECHNOLOGY_ENABLED) { + NET_LOG(ERROR) << "UpdateTetherNetworkProperties() called when Tether " + << "networks are not enabled. Cannot update."; + return false; + } + NetworkState* tether_network_state = GetModifiableNetworkStateFromGuid(guid); if (!tether_network_state) return false; @@ -494,6 +573,13 @@ bool NetworkStateHandler::AssociateTetherNetworkStateWithWifiNetwork( const std::string& tether_network_guid, const std::string& wifi_network_guid) { + if (tether_technology_state_ != TECHNOLOGY_ENABLED) { + NET_LOG(ERROR) << "AssociateTetherNetworkStateWithWifiNetwork() called " + << "when Tether networks are not enabled. Cannot " + << "associate."; + return false; + } + NetworkState* tether_network = GetModifiableNetworkStateFromGuid(tether_network_guid); if (!tether_network) { @@ -525,14 +611,14 @@ void NetworkStateHandler::SetTetherNetworkStateDisconnected( const std::string& guid) { - // TODO(khorimoto): Remove the tether network as the default network, and + // TODO(khorimoto): Remove the Tether network as the default network, and // send a connection status change. SetTetherNetworkStateConnectionState(guid, shill::kStateDisconnect); } void NetworkStateHandler::SetTetherNetworkStateConnecting( const std::string& guid) { - // TODO(khorimoto): Set the tether network as the default network, and send + // TODO(khorimoto): Set the Tether network as the default network, and send // a connection status change. SetTetherNetworkStateConnectionState(guid, shill::kStateConfiguration); } @@ -564,6 +650,41 @@ NotifyNetworkListChanged(); } +void NetworkStateHandler::EnsureTetherDeviceState() { + bool should_be_present = + tether_technology_state_ != TechnologyState::TECHNOLOGY_UNAVAILABLE; + + for (auto it = device_list_.begin(); it < device_list_.end(); ++it) { + std::string path = (*it)->path(); + if (path == kTetherDevicePath) { + // If the Tether DeviceState is in the list and it should not be, remove + // it and return. If it is in the list and it should be, the list is + // already valid, so return without removing it. + if (!should_be_present) + device_list_.erase(it); + return; + } + } + + if (!should_be_present) { + // If the Tether DeviceState was not in the list and it should not be, the + // list is already valid, so return. + return; + } + + // The Tether DeviceState is not present in the list, but it should be. Since + // Tether networks are not recognized by Shill, they will never receive an + // update, so set properties on the state here. + std::unique_ptr<ManagedState> tether_device_state = ManagedState::Create( + ManagedState::ManagedType::MANAGED_TYPE_DEVICE, kTetherDevicePath); + tether_device_state->set_update_received(); + tether_device_state->set_update_requested(false); + tether_device_state->set_name(kTetherDeviceName); + tether_device_state->set_type(kTypeTether); + + device_list_.push_back(std::move(tether_device_state)); +} + void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const { GetDeviceListByType(NetworkTypePattern::Default(), list); } @@ -572,6 +693,7 @@ DeviceStateList* list) const { DCHECK(list); list->clear(); + for (auto iter = device_list_.begin(); iter != device_list_.end(); ++iter) { const DeviceState* device = (*iter)->AsDeviceState(); DCHECK(device); @@ -726,6 +848,17 @@ list_entries.insert(path); } + if (type == ManagedState::ManagedType::MANAGED_TYPE_DEVICE) { + // Also move the Tether DeviceState if it exists. This will not happen as + // part of the loop above since |entries| will never contain the Tether + // path. + auto iter = managed_map.find(kTetherDevicePath); + if (iter != managed_map.end()) { + managed_list->push_back(std::move(iter->second)); + managed_map.erase(iter); + } + } + if (type != ManagedState::ManagedType::MANAGED_TYPE_NETWORK) return; @@ -971,7 +1104,7 @@ } } -// TODO(khorimoto): Add sorting for the tether network list as well. +// TODO(khorimoto): Add sorting for the Tether network list as well. void NetworkStateHandler::SortNetworkList() { // Note: usually active networks will precede inactive networks, however // this may briefly be untrue during state transitions (e.g. a network may @@ -1275,6 +1408,8 @@ technologies.emplace_back(shill::kTypeBluetooth); if (type.MatchesType(shill::kTypeVPN)) technologies.emplace_back(shill::kTypeVPN); + if (type.MatchesType(kTypeTether)) + technologies.emplace_back(kTypeTether); CHECK_GT(technologies.size(), 0ul); return technologies;
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h index 3265b00..b35887b 100644 --- a/chromeos/network/network_state_handler.h +++ b/chromeos/network/network_state_handler.h
@@ -112,6 +112,17 @@ bool enabled, const network_handler::ErrorCallback& error_callback); + // Sets the tether technology state. Because Tether networks do not represent + // real Shill networks, this value must be set by the tether component rather + // than being generated by Shill. See TetherDeviceStateManager for more + // details. + void SetTetherTechnologyState(TechnologyState technology_state); + + // Sets the scanning state of the tether technology. Since tether network + // scans are not actually performed as part of Shill, this value must be set + // by the tether component. + void SetTetherScanState(bool is_scanning); + // Asynchronously sets the list of prohibited technologies. The accepted // values are the shill network technology identifiers. See also // chromeos::onc::Validator::ValidateGlobalNetworkConfiguration(). @@ -250,7 +261,9 @@ DeviceStateList* list) const; // Requests a network scan. This may trigger updates to the network - // list, which will trigger the appropriate observer calls. + // list, which will trigger the appropriate observer calls. Note that this + // function does not request a tether scan. + // TODO(khorimoto): Add ability to request a tether scan as well. void RequestScan() const; // Requests an update for an existing NetworkState, e.g. after configuring @@ -259,7 +272,7 @@ // acknowledged it (e.g. in the callback of a SetProperties). // When the properties are received, NetworkPropertiesUpdated will be // signaled for each member of |observers_|, regardless of whether any - // properties actually changed. + // properties actually changed. Note that this is a no-op for Tether networks. void RequestUpdateForNetwork(const std::string& service_path); // Informs NetworkStateHandler to notify observers that the properties for @@ -452,6 +465,11 @@ const std::string& guid, const std::string& connection_state); + // Ensures that the Tether DeviceState is present in |device_list_| if + // |tether_technology_state_| is not TECHNOLOGY_UNAVAILABLE and ensures that + // it is not present in |device_list_| if it is TECHNOLOGY_UNAVAILABLE. + void EnsureTetherDeviceState(); + // Shill property handler instance, owned by this class. std::unique_ptr<internal::ShillPropertyHandler> shill_property_handler_; @@ -482,6 +500,11 @@ // NetworkState that is not saved in a profile. SpecifierGuidMap specifier_guid_map_; + // The state corresponding to the tether device type. This value is managed by + // the tether component. + TechnologyState tether_technology_state_ = + TechnologyState::TECHNOLOGY_UNAVAILABLE; + // Ensure that Shutdown() gets called exactly once. bool did_shutdown_ = false;
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc index 0d1df22..0502606b 100644 --- a/chromeos/network/network_state_handler_unittest.cc +++ b/chromeos/network/network_state_handler_unittest.cc
@@ -28,6 +28,7 @@ #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" +#include "chromeos/network/tether_constants.h" #include "dbus/object_path.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -73,8 +74,8 @@ device_count_(0), network_list_changed_count_(0), network_count_(0), - default_network_change_count_(0) { - } + default_network_change_count_(0), + scan_completed_count_(0) {} ~TestObserver() override {} @@ -125,6 +126,11 @@ device_property_updates_[device->path()]++; } + void ScanCompleted(const DeviceState* device) override { + DCHECK(device); + scan_completed_count_++; + } + size_t device_list_changed_count() { return device_list_changed_count_; } size_t device_count() { return device_count_; } size_t network_list_changed_count() { return network_list_changed_count_; } @@ -132,11 +138,13 @@ size_t default_network_change_count() { return default_network_change_count_; } + size_t scan_completed_count() { return scan_completed_count_; } void reset_change_counts() { DVLOG(1) << "=== RESET CHANGE COUNTS ==="; default_network_change_count_ = 0; device_list_changed_count_ = 0; network_list_changed_count_ = 0; + scan_completed_count_ = 0; connection_state_changes_.clear(); } void reset_updates() { @@ -172,6 +180,7 @@ size_t network_list_changed_count_; size_t network_count_; size_t default_network_change_count_; + size_t scan_completed_count_; std::string default_network_; std::string default_network_connection_state_; std::map<std::string, int> property_updates_; @@ -330,6 +339,9 @@ } TEST_F(NetworkStateHandlerTest, GetNetworkList) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + // Ensure that the network list is the expected size. const size_t kNumShillManagerClientStubImplServices = 4; EXPECT_EQ(kNumShillManagerClientStubImplServices, @@ -415,6 +427,9 @@ } TEST_F(NetworkStateHandlerTest, GetTetherNetworkList) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + NetworkStateHandler::NetworkStateList tether_networks; GetTetherNetworkList(0 /* no limit */, &tether_networks); @@ -568,13 +583,80 @@ EXPECT_EQ( NetworkStateHandler::TECHNOLOGY_UNAVAILABLE, network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_FALSE(network_state_handler_->GetDeviceState(kTetherDevicePath)); + EXPECT_FALSE(network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether())); - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableTether); + // Test SetTetherTechnologyState(): + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_AVAILABLE); + EXPECT_EQ(1u, test_observer_->device_list_changed_count()); + EXPECT_EQ( + NetworkStateHandler::TECHNOLOGY_AVAILABLE, + network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether())); + const DeviceState* tether_device_state = + network_state_handler_->GetDeviceState(kTetherDevicePath); + EXPECT_TRUE(tether_device_state); + EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether())); + // Test SetTechnologyEnabled() with a tether network: + network_state_handler_->SetTechnologyEnabled( + NetworkTypePattern::Tether(), true, network_handler::ErrorCallback()); + EXPECT_EQ(2u, test_observer_->device_list_changed_count()); EXPECT_EQ( NetworkStateHandler::TECHNOLOGY_ENABLED, network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_EQ(tether_device_state, + network_state_handler_->GetDeviceState(kTetherDevicePath)); + EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether())); + + // Test SetProhibitedTechnologies() with a tether network: + network_state_handler_->SetProhibitedTechnologies( + std::vector<std::string>{kTypeTether}, network_handler::ErrorCallback()); + EXPECT_EQ(3u, test_observer_->device_list_changed_count()); + EXPECT_EQ( + NetworkStateHandler::TECHNOLOGY_PROHIBITED, + network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether())); + EXPECT_EQ(tether_device_state, + network_state_handler_->GetDeviceState(kTetherDevicePath)); + EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether())); + + // Set back to TECHNOLOGY_UNAVAILABLE; this should result in nullptr being + // returned by getters. + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_UNAVAILABLE); + EXPECT_FALSE(network_state_handler_->GetDeviceState(kTetherDevicePath)); + EXPECT_FALSE(network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether())); +} + +TEST_F(NetworkStateHandlerTest, TetherScanningState) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + + const DeviceState* tether_device_state = + network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether()); + EXPECT_TRUE(tether_device_state); + EXPECT_FALSE(tether_device_state->scanning()); + EXPECT_EQ(0u, test_observer_->scan_completed_count()); + + network_state_handler_->SetTetherScanState(true /* is_scanning */); + tether_device_state = network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether()); + EXPECT_TRUE(tether_device_state); + EXPECT_TRUE(tether_device_state->scanning()); + EXPECT_EQ(0u, test_observer_->scan_completed_count()); + + network_state_handler_->SetTetherScanState(false /* is_scanning */); + tether_device_state = network_state_handler_->GetDeviceStateByType( + NetworkTypePattern::Tether()); + EXPECT_TRUE(tether_device_state); + EXPECT_FALSE(tether_device_state->scanning()); + EXPECT_EQ(1u, test_observer_->scan_completed_count()); } TEST_F(NetworkStateHandlerTest, ServicePropertyChanged) { @@ -625,6 +707,9 @@ } TEST_F(NetworkStateHandlerTest, TetherNetworkState) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + EXPECT_EQ(0u, test_observer_->network_list_changed_count()); network_state_handler_->AddTetherNetworkState( @@ -671,6 +756,9 @@ } TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + EXPECT_EQ(0u, test_observer_->network_list_changed_count()); const std::string profile = "/profile/profile1"; @@ -712,6 +800,9 @@ } TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociationWifiRemoved) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + const std::string profile = "/profile/profile1"; const std::string wifi_path = "/service/wifi_with_guid"; AddService(wifi_path, kWifiGuid1, kWifiName1, shill::kTypeWifi, @@ -744,6 +835,9 @@ } TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation_NoWifiNetwork) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + network_state_handler_->AddTetherNetworkState( kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1, kTetherSignalStrength1); @@ -754,6 +848,9 @@ } TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation_NoTetherNetwork) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + const std::string profile = "/profile/profile1"; const std::string wifi_path = "/service/wifi_with_guid"; AddService(wifi_path, kWifiGuid1, kWifiName1, shill::kTypeWifi, @@ -768,6 +865,9 @@ } TEST_F(NetworkStateHandlerTest, SetTetherNetworkStateConnectionState) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + network_state_handler_->AddTetherNetworkState( kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1, kTetherSignalStrength1);
diff --git a/chromeos/network/tether_constants.cc b/chromeos/network/tether_constants.cc index 70867b5a1..72fd96b 100644 --- a/chromeos/network/tether_constants.cc +++ b/chromeos/network/tether_constants.cc
@@ -10,5 +10,7 @@ const char kTetherBatteryPercentage[] = "Tether.BatteryPercentage"; const char kTetherCarrier[] = "Tether.Carrier"; const char kTetherSignalStrength[] = "Tether.SignalStrength"; +const char kTetherDevicePath[] = "tether-device-path"; +const char kTetherDeviceName[] = "tether-name"; } // namespace chromeos
diff --git a/chromeos/network/tether_constants.h b/chromeos/network/tether_constants.h index 26b4f21d..4d73d1d 100644 --- a/chromeos/network/tether_constants.h +++ b/chromeos/network/tether_constants.h
@@ -22,6 +22,12 @@ CHROMEOS_EXPORT extern const char kTetherCarrier[]; CHROMEOS_EXPORT extern const char kTetherSignalStrength[]; +// The device path used for the tether DeviceState. +CHROMEOS_EXPORT extern const char kTetherDevicePath[]; + +// The name used for the tether DeviceState. +CHROMEOS_EXPORT extern const char kTetherDeviceName[]; + } // namespace chromeos #endif // CHROMEOS_NETWORK_TETHER_CONSTANTS_H_
diff --git a/components/arc/common/voice_interaction_framework.mojom b/components/arc/common/voice_interaction_framework.mojom index adf25f4..38fb2ec 100644 --- a/components/arc/common/voice_interaction_framework.mojom +++ b/components/arc/common/voice_interaction_framework.mojom
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 2 +// Next MinVersion: 3 module arc.mojom; import "screen_rect.mojom"; // Handles voice interaction queries from Android. -// Next method ID: 2 +// Next method ID: 3 interface VoiceInteractionFrameworkHost { // Returns a screenshot of currently focused window or empty array if // no window is focused. @@ -17,10 +17,13 @@ // Returns a fullscreen screenshot of the primary display. [MinVersion=1]CaptureFullscreen@1() => (array<uint8> png_data); + + // Notifies the host that the metalayer has closed or could not open. + [MinVersion=2]OnMetalayerClosed@2(); }; // Connects with Android system server. -// Next method ID:4 +// Next method ID: 4 interface VoiceInteractionFrameworkInstance { Init@0(VoiceInteractionFrameworkHost host_ptr); @@ -31,6 +34,6 @@ // selected. [MinVersion=1] StartVoiceInteractionSessionForRegion@2(ScreenRect region); - // Toggles the metalayer. - [MinVersion=1] ToggleMetalayer@3(); + // Shows/hides the metalayer in the container. + [MinVersion=1] SetMetalayerVisibility@3([MinVersion=2] bool visible); };
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc index 6e09db8..fd4f3f6 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -7,8 +7,7 @@ namespace data_reduction_proxy { namespace features { -// Enables the Data Reduction Proxy menu item in the main menu rather than under -// Settings on Android. +// Enables the Data Reduction Proxy footer in the main menu on Android. const base::Feature kDataReductionMainMenu{"DataReductionProxyMainMenu", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/storage_monitor/media_storage_util.cc b/components/storage_monitor/media_storage_util.cc index 5dbfdcc..7841e4e29 100644 --- a/components/storage_monitor/media_storage_util.cc +++ b/components/storage_monitor/media_storage_util.cc
@@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/files/file_util.h" #include "base/logging.h" -#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -23,19 +22,6 @@ namespace { -// MediaDeviceNotification.DeviceInfo histogram values. -enum DeviceInfoHistogramBuckets { - MASS_STORAGE_DEVICE_NAME_AND_UUID_AVAILABLE, - MASS_STORAGE_DEVICE_UUID_MISSING, - MASS_STORAGE_DEVICE_NAME_MISSING, - MASS_STORAGE_DEVICE_NAME_AND_UUID_MISSING, - MTP_STORAGE_DEVICE_NAME_AND_UUID_AVAILABLE, - MTP_STORAGE_DEVICE_UUID_MISSING, - MTP_STORAGE_DEVICE_NAME_MISSING, - MTP_STORAGE_DEVICE_NAME_AND_UUID_MISSING, - DEVICE_INFO_BUCKET_BOUNDARY -}; - #if !defined(OS_WIN) const char kRootPath[] = "/"; #endif @@ -213,30 +199,6 @@ } // static -void MediaStorageUtil::RecordDeviceInfoHistogram( - bool mass_storage, - const std::string& device_uuid, - const base::string16& device_label) { - unsigned int event_number = 0; - if (!mass_storage) - event_number = 4; - - if (device_label.empty()) - event_number += 2; - - if (device_uuid.empty()) - event_number += 1; - enum DeviceInfoHistogramBuckets event = - static_cast<enum DeviceInfoHistogramBuckets>(event_number); - if (event >= DEVICE_INFO_BUCKET_BOUNDARY) { - NOTREACHED(); - return; - } - UMA_HISTOGRAM_ENUMERATION("MediaDeviceNotifications.DeviceInfo", event, - DEVICE_INFO_BUCKET_BOUNDARY); -} - -// static bool MediaStorageUtil::IsRemovableStorageAttached(const std::string& id) { StorageMonitor* monitor = StorageMonitor::GetInstance(); if (!monitor)
diff --git a/components/storage_monitor/media_storage_util.h b/components/storage_monitor/media_storage_util.h index 99c14d6..6b0bb74 100644 --- a/components/storage_monitor/media_storage_util.h +++ b/components/storage_monitor/media_storage_util.h
@@ -50,13 +50,6 @@ // the device is connected. static base::FilePath FindDevicePathById(const std::string& device_id); - // Record device information histogram for the given |device_uuid| and - // |device_label|. |mass_storage| indicates whether the current device is a - // mass storage device, as defined by IsMassStorageDevice(). - static void RecordDeviceInfoHistogram(bool mass_storage, - const std::string& device_uuid, - const base::string16& device_label); - // Returns true if the |id| is both a removable device and also // currently attached. static bool IsRemovableStorageAttached(const std::string& id);
diff --git a/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc b/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc index 0616199..3a67e27 100644 --- a/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc +++ b/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
@@ -11,7 +11,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" -#include "components/storage_monitor/media_storage_util.h" #include "components/storage_monitor/removable_device_constants.h" #include "device/media_transfer_protocol/mtp_storage_info.pb.h" @@ -202,10 +201,6 @@ &storage_label, &location, &vendor_name, &product_name); - // Keep track of device id and device name to see how often we receive - // empty values. - MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id, - storage_label); if (device_id.empty() || storage_label.empty()) return;
diff --git a/components/storage_monitor/portable_device_watcher_win.cc b/components/storage_monitor/portable_device_watcher_win.cc index 44d2885..368c4cf2 100644 --- a/components/storage_monitor/portable_device_watcher_win.cc +++ b/components/storage_monitor/portable_device_watcher_win.cc
@@ -20,7 +20,6 @@ #include "base/win/scoped_co_mem.h" #include "base/win/scoped_comptr.h" #include "base/win/scoped_propvariant.h" -#include "components/storage_monitor/media_storage_util.h" #include "components/storage_monitor/removable_device_constants.h" #include "components/storage_monitor/storage_info.h" #include "content/public/browser/browser_thread.h" @@ -632,9 +631,6 @@ const std::string& storage_id = storage_iter->object_persistent_id; DCHECK(!base::ContainsKey(storage_map_, storage_id)); - // Keep track of storage id and storage name to see how often we receive - // empty values. - MediaStorageUtil::RecordDeviceInfoHistogram(false, storage_id, name); if (storage_id.empty() || name.empty()) return;
diff --git a/components/storage_monitor/storage_monitor_chromeos.cc b/components/storage_monitor/storage_monitor_chromeos.cc index 228cc440..edce2a5 100644 --- a/components/storage_monitor/storage_monitor_chromeos.cc +++ b/components/storage_monitor/storage_monitor_chromeos.cc
@@ -57,10 +57,6 @@ return false; std::string unique_id = MakeDeviceUniqueId(*disk); - // Keep track of device uuid and label, to see how often we receive empty - // values. - base::string16 device_label = base::UTF8ToUTF16(disk->device_label()); - MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, device_label); if (unique_id.empty()) return false; @@ -68,12 +64,11 @@ StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM : StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM; - *info = StorageInfo(StorageInfo::MakeDeviceId(type, unique_id), - mount_info.mount_path, - device_label, - base::UTF8ToUTF16(disk->vendor_name()), - base::UTF8ToUTF16(disk->product_name()), - disk->total_size_in_bytes()); + *info = StorageInfo( + StorageInfo::MakeDeviceId(type, unique_id), mount_info.mount_path, + base::UTF8ToUTF16(disk->device_label()), + base::UTF8ToUTF16(disk->vendor_name()), + base::UTF8ToUTF16(disk->product_name()), disk->total_size_in_bytes()); return true; }
diff --git a/components/storage_monitor/storage_monitor_linux.cc b/components/storage_monitor/storage_monitor_linux.cc index 1bbffa9..f0f53d7 100644 --- a/components/storage_monitor/storage_monitor_linux.cc +++ b/components/storage_monitor/storage_monitor_linux.cc
@@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/process/kill.h" #include "base/process/launch.h" @@ -54,11 +55,6 @@ // Construct a device id using label or manufacturer (vendor and model) details. std::string MakeDeviceUniqueId(struct udev_device* device) { std::string uuid = device::UdevDeviceGetPropertyValue(device, kFsUUID); - // Keep track of device uuid, to see how often we receive empty uuid values. - UMA_HISTOGRAM_BOOLEAN( - "RemovableDeviceNotificationsLinux.device_file_system_uuid_available", - !uuid.empty()); - if (!uuid.empty()) return kFSUniqueIdPrefix + uuid; @@ -104,12 +100,6 @@ const std::string partition_size = device::UdevDeviceGetSysattrValue(device, kSizeSysAttr); - // Keep track of device size, to see how often this information is - // unavailable. - UMA_HISTOGRAM_BOOLEAN( - "RemovableDeviceNotificationsLinux.device_partition_size_available", - !partition_size.empty()); - uint64_t total_size_in_bytes = 0; if (!base::StringToUint64(partition_size, &total_size_in_bytes)) return 0; @@ -158,10 +148,6 @@ device::UdevDeviceGetPropertyValue(device.get(), kModel)); std::string unique_id = MakeDeviceUniqueId(device.get()); - - // Keep track of device info details to see how often we get invalid values. - MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, volume_label); - const char* value = device::udev_device_get_sysattr_value(device.get(), kRemovableSysAttr); if (!value) { @@ -179,21 +165,17 @@ StorageInfo::Type type = StorageInfo::FIXED_MASS_STORAGE; if (is_removable) { - if (MediaStorageUtil::HasDcim(mount_point)) - type = StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM; - else - type = StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM; + type = MediaStorageUtil::HasDcim(mount_point) + ? StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM + : StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM; } results_recorder.set_result(true); - storage_info.reset(new StorageInfo( - StorageInfo::MakeDeviceId(type, unique_id), - mount_point.value(), - volume_label, - vendor_name, - model_name, - GetDeviceStorageSize(device_path, device.get()))); + storage_info = base::MakeUnique<StorageInfo>( + StorageInfo::MakeDeviceId(type, unique_id), mount_point.value(), + volume_label, vendor_name, model_name, + GetDeviceStorageSize(device_path, device.get())); return storage_info; }
diff --git a/components/storage_monitor/storage_monitor_mac.mm b/components/storage_monitor/storage_monitor_mac.mm index 47d9135..a48b024 100644 --- a/components/storage_monitor/storage_monitor_mac.mm +++ b/components/storage_monitor/storage_monitor_mac.mm
@@ -238,8 +238,6 @@ disk_info_map_.erase(it); } else { disk_info_map_[bsd_name] = info; - MediaStorageUtil::RecordDeviceInfoHistogram(true, info.device_id(), - info.storage_label()); if (ShouldPostNotificationForDisk(info)) receiver()->ProcessAttach(info); }
diff --git a/components/storage_monitor/volume_mount_watcher_win.cc b/components/storage_monitor/volume_mount_watcher_win.cc index 5ac0b11..17e7a630 100644 --- a/components/storage_monitor/volume_mount_watcher_win.cc +++ b/components/storage_monitor/volume_mount_watcher_win.cc
@@ -16,7 +16,6 @@ #include <algorithm> #include "base/bind_helpers.h" -#include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -47,15 +46,6 @@ FIXED, }; -// Histogram values for recording frequencies of eject attempts and -// outcomes. -enum EjectWinLockOutcomes { - LOCK_ATTEMPT, - LOCK_TIMEOUT, - LOCK_TIMEOUT2, - NUM_LOCK_OUTCOMES, -}; - // We are trying to figure out whether the drive is a fixed volume, // a removable storage, or a floppy. A "floppy" here means "a volume we // want to basically ignore because it won't fit media and will spin @@ -262,12 +252,7 @@ // handle is closed, and this is done by the ScopedHandle above. BOOL locked = DeviceIoControl(volume_handle.Get(), FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL); - UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", - LOCK_ATTEMPT, NUM_LOCK_OUTCOMES); if (!locked) { - UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", - iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2, - NUM_LOCK_OUTCOMES); const int kNumLockRetries = 1; const base::TimeDelta kLockRetryInterval = base::TimeDelta::FromMilliseconds(500);
diff --git a/components/sync/protocol/session_specifics.proto b/components/sync/protocol/session_specifics.proto index 04df7d31..622309b 100644 --- a/components/sync/protocol/session_specifics.proto +++ b/components/sync/protocol/session_specifics.proto
@@ -155,6 +155,18 @@ } // Whether the Password Manager saw a password field on the page. optional PasswordState password_state = 26; + + // The id for the task associated with this navigation, which is globally + // unique with high probability. + // Similar with global_id, but used to identify a navigation in Chrome Tasks, + // so navigations of a page have the same task_id if one is the first visit of + // the page, and others are its back/forward visits. + optional int64 task_id = 27; + // Task ids of all ancestor navigations, which can be from other tabs, from + // root to parent. We define navigation A is parent of navigation B if page of + // B is got by clicking a link on page of A. This relationship is used to + // define a Chrome Task as a tree rooted by a navigation. + repeated int64 ancestor_task_id = 28; } // Navigation information for a single redirection within a single navigation.
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn index 8d912876..7212996 100644 --- a/components/sync_sessions/BUILD.gn +++ b/components/sync_sessions/BUILD.gn
@@ -48,6 +48,8 @@ "synced_window_delegates_getter.h", "tab_node_pool.cc", "tab_node_pool.h", + "task_tracker.cc", + "task_tracker.h", ] public_deps = [ @@ -104,6 +106,7 @@ "sync_sessions_metrics_unittest.cc", "synced_session_tracker_unittest.cc", "tab_node_pool_unittest.cc", + "task_tracker_unittest.cc", ] deps = [
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc index f37c1b3..f985b3db 100644 --- a/components/sync_sessions/sessions_sync_manager.cc +++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -156,7 +156,8 @@ local_event_router_(std::move(router)), page_revisit_broadcaster_(this, sessions_client), sessions_updated_callback_(sessions_updated_callback), - datatype_refresh_callback_(datatype_refresh_callback) {} + datatype_refresh_callback_(datatype_refresh_callback), + task_tracker_(base::MakeUnique<TaskTracker>()) {} SessionsSyncManager::~SessionsSyncManager() {} @@ -422,8 +423,9 @@ DCHECK(!tab_delegate->IsPlaceholderTab()); if (tab_delegate->IsBeingDestroyed()) { - // Do nothing. By not proactively adding the tab to the session, it will be - // removed if necessary during subsequent cleanup. + task_tracker_->CleanTabTasks(tab_delegate->GetSessionId()); + // Do nothing else. By not proactively adding the tab to the session, it + // will be removed if necessary during subsequent cleanup. return; } @@ -464,6 +466,9 @@ sync_pb::EntitySpecifics specifics; specifics.mutable_session()->CopyFrom( SessionTabToSpecifics(*session_tab, current_machine_tag(), tab_node_id)); + // Intercept the sync model here to update task tracker and fill navigations + // with their ancestor navigations. + TrackTasks(tab_delegate, specifics.mutable_session()); syncer::SyncData data = syncer::SyncData::CreateLocalData( TabNodeIdToTag(current_machine_tag(), tab_node_id), current_session_name_, specifics); @@ -483,6 +488,54 @@ } } +void SessionsSyncManager::TrackTasks( + SyncedTabDelegate* const tab_delegate, + sync_pb::SessionSpecifics* session_specifics) { + sync_pb::SessionTab* tab_specifics = session_specifics->mutable_tab(); + // Index in the whole navigations of the tab. + int current_navigation_index = tab_delegate->GetCurrentEntryIndex(); + // Index in the tab_specifics, where the navigations is a -6/+6 window + int current_index_in_tab_specifics = + tab_specifics->current_navigation_index(); + int64_t current_navigation_global_id = + tab_specifics->navigation(current_index_in_tab_specifics).global_id(); + + TabTasks* tab_tasks = + task_tracker_->GetTabTasks(tab_delegate->GetSessionId()); + tab_tasks->UpdateWithNavigation( + current_navigation_index, + tab_delegate->GetTransitionAtIndex(current_navigation_index), + current_navigation_global_id); + + for (int i = 0; i < tab_specifics->navigation_size(); i++) { + // Excluding blocked navigations, which are appended at tail. + if (tab_specifics->navigation(i).blocked_state() == + sync_pb::TabNavigation::STATE_BLOCKED) { + break; + } + + int navigation_index = + current_navigation_index - current_index_in_tab_specifics + i; + // Skipping navigations not been tracked by task_tracker. + if (navigation_index < 0 || + navigation_index >= tab_tasks->GetNavigationsCount()) { + continue; + } + std::vector<int64_t> task_ids = + tab_tasks->GetTaskIdsForNavigation(navigation_index); + if (task_ids.empty()) + continue; + + tab_specifics->mutable_navigation(i)->set_task_id(task_ids.back()); + // Pop the task id of navigation self. + task_ids.pop_back(); + for (auto ancestor_task_id : task_ids) { + tab_specifics->mutable_navigation(i)->add_ancestor_task_id( + ancestor_task_id); + } + } +} + bool SessionsSyncManager::RebuildAssociations() { syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS)); std::unique_ptr<syncer::SyncErrorFactory> error_handler(
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h index 80706d86..3c5e5fe 100644 --- a/components/sync_sessions/sessions_sync_manager.h +++ b/components/sync_sessions/sessions_sync_manager.h
@@ -30,6 +30,7 @@ #include "components/sync_sessions/revisit/page_revisit_broadcaster.h" #include "components/sync_sessions/synced_session.h" #include "components/sync_sessions/synced_session_tracker.h" +#include "components/sync_sessions/task_tracker.h" namespace syncer { class LocalDeviceInfoProvider; @@ -235,6 +236,11 @@ void LocalTabDelegateToSpecifics(const SyncedTabDelegate& tab_delegate, sync_pb::SessionSpecifics* specifics); + // Updates task tracker with current navigation of |tab_delegate|, and fills + // TabNavigation's task id related fields in |specifics|. + void TrackTasks(SyncedTabDelegate* const tab_delegate, + sync_pb::SessionSpecifics* specifics); + // It's possible that when we associate windows, tabs aren't all loaded // into memory yet (e.g on android) and we don't have a WebContents. In this // case we can't do a full association, but we still want to update tab IDs @@ -326,6 +332,10 @@ // Callback to inform sync that a sync data refresh is requested. base::Closure datatype_refresh_callback_; + // Tracks Chrome Tasks, which associates navigations, with tab and navigation + // changes of current session. + std::unique_ptr<TaskTracker> task_tracker_; + DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager); };
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc index bc22ca115..41c3eada 100644 --- a/components/sync_sessions/sessions_sync_manager_unittest.cc +++ b/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -707,21 +707,34 @@ } TestSyncedTabDelegate* AddTab(SessionID::id_type window_id, const std::string& url) { - return AddTab(window_id, url, base::Time()); + return AddTab(window_id, url, base::Time::Now()); } void NavigateTab(TestSyncedTabDelegate* delegate, const std::string& url, - base::Time time) { + base::Time time, + ui::PageTransition transition) { auto entry = base::MakeUnique<sessions::SerializedNavigationEntry>( SerializedNavigationEntryTestHelper::CreateNavigation(url, kTitle)); SerializedNavigationEntryTestHelper::SetTimestamp(time, entry.get()); + SerializedNavigationEntryTestHelper::SetTransitionType(transition, + entry.get()); delegate->AppendEntry(std::move(entry)); delegate->set_current_entry_index(delegate->GetCurrentEntryIndex() + 1); router_->NotifyNav(delegate); } + void NavigateTab(TestSyncedTabDelegate* delegate, + const std::string& url, + base::Time time) { + NavigateTab(delegate, url, time, ui::PAGE_TRANSITION_TYPED); + } void NavigateTab(TestSyncedTabDelegate* delegate, const std::string& url) { - NavigateTab(delegate, url, base::Time()); + NavigateTab(delegate, url, base::Time::Now()); + } + void NavigateTab(TestSyncedTabDelegate* delegate, + const std::string& url, + ui::PageTransition transition) { + NavigateTab(delegate, url, base::Time::Now(), transition); } void ResetWindows() { @@ -2532,4 +2545,53 @@ out[1].sync_data().GetSpecifics().session().tab().window_id()); } +// Tests that task ids are generated for navigations on local tabs. +TEST_F(SessionsSyncManagerTest, TrackTasksOnLocalTabModified) { + SyncChangeList changes; + TestSyncedWindowDelegate* window = AddWindow(); + InitWithSyncDataTakeOutput(SyncDataList(), &changes); + SessionID::id_type window_id = window->GetSessionId(); + ASSERT_FALSE(manager()->current_machine_tag().empty()); + changes.clear(); + + // Tab 1 + NavigateTab(AddTab(window_id, kFoo1), kFoo2, ui::PAGE_TRANSITION_TYPED); + // Tab 2 + NavigateTab(AddTab(window_id, kBar1), kBar2, ui::PAGE_TRANSITION_LINK); + + // We only test changes for tab add and tab update, and ignore header updates. + FilterOutLocalHeaderChanges(&changes); + // Sync data of adding Tab 1 change + sync_pb::SessionTab tab = + SyncDataLocal(changes[0].sync_data()).GetSpecifics().session().tab(); + EXPECT_EQ(tab.navigation_size(), 1); + EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id()); + EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty()); + + // Sync data of updating Tab 1 change + tab = SyncDataLocal(changes[1].sync_data()).GetSpecifics().session().tab(); + EXPECT_EQ(tab.navigation_size(), 2); + // navigation(0) and navigation(1) are two seperated tasks. + EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id()); + EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty()); + EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id()); + EXPECT_TRUE(tab.navigation(1).ancestor_task_id().empty()); + + // Sync data of adding Tab 2 change + tab = SyncDataLocal(changes[2].sync_data()).GetSpecifics().session().tab(); + EXPECT_EQ(tab.navigation_size(), 1); + EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id()); + EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty()); + + // Sync data of updating Tab 2 change + tab = SyncDataLocal(changes[3].sync_data()).GetSpecifics().session().tab(); + EXPECT_EQ(tab.navigation_size(), 2); + EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id()); + EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty()); + EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id()); + // navigation(1) is a subtask of navigation(0). + EXPECT_EQ(tab.navigation(1).ancestor_task_id_size(), 1); + EXPECT_EQ(tab.navigation(1).ancestor_task_id(0), tab.navigation(0).task_id()); +} + } // namespace sync_sessions
diff --git a/components/sync_sessions/task_tracker.cc b/components/sync_sessions/task_tracker.cc new file mode 100644 index 0000000..0f8902e2 --- /dev/null +++ b/components/sync_sessions/task_tracker.cc
@@ -0,0 +1,173 @@ +// 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 "components/sync_sessions/task_tracker.h" + +#include <utility> + +#include "base/numerics/safe_conversions.h" + +namespace sync_sessions { + +namespace { +// The maximum number of tasks we track in a tab. +int kMaxNumTasksPerTab = 100; +} + +TabTasks::TabTasks() {} + +TabTasks::~TabTasks() {} + +std::vector<int64_t> TabTasks::GetTaskIdsForNavigation( + int navigation_index) const { + CHECK_LE(0, navigation_index); + CHECK_LT(navigation_index, GetNavigationsCount()); + + std::vector<int64_t> root_to_self_task_ids; + // Position of the navigation in task_ids_ vector. + int navigation_position = navigation_index - excluded_navigation_num_; + + // If navigation_index is an excluded ancestor task, returns empty. + if (navigation_position < 0) + return root_to_self_task_ids; + + TaskIdAndRoot task_id_and_root = task_ids_[navigation_position]; + + // If navigation_index is an invalid task, returns empty. + if (task_id_and_root.root_navigation_index < 0) + return root_to_self_task_ids; + + // The root task can be excluded. If so, consider the oldest ancestor + // available as root. + int root_navigation_index = + task_id_and_root.root_navigation_index > excluded_navigation_num_ + ? task_id_and_root.root_navigation_index - excluded_navigation_num_ + : 0; + for (int i = root_navigation_index; i <= navigation_position; i++) { + // Fills the vector with valid tasks. + if (task_ids_[i].root_navigation_index >= 0) + root_to_self_task_ids.push_back(task_ids_[i].task_id); + } + return root_to_self_task_ids; +} + +int TabTasks::GetNavigationsCount() const { + return excluded_navigation_num_ + task_ids_.size(); +} + +void TabTasks::UpdateWithNavigation(int navigation_index, + ui::PageTransition transition, + int64_t navigation_id) { + // Triggered by some notifications on the current page, do nothing. + if (navigation_index == current_navigation_index_) { + DVLOG(1) << "Doing nothing for navigation_index: " << navigation_index + << " of transition: " << transition; + return; + } + + // Going back/forward to some previous navigation. + if (navigation_index < current_navigation_index_ || + (navigation_index > current_navigation_index_ && + transition & ui::PAGE_TRANSITION_FORWARD_BACK && + base::checked_cast<size_t>(navigation_index) < task_ids_.size())) { + DVLOG(1) << "Just updating task position with navigation_index: " + << navigation_index << " of transition: " << transition; + current_navigation_index_ = navigation_index; + return; + } + + // A new task for the new navigation. + int root_navigation_index = navigation_index; + if (current_navigation_index_ != -1 && + (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK) || + ui::PageTransitionCoreTypeIs(transition, + ui::PAGE_TRANSITION_AUTO_SUBFRAME) || + ui::PageTransitionCoreTypeIs(transition, + ui::PAGE_TRANSITION_MANUAL_SUBFRAME) || + ui::PageTransitionCoreTypeIs(transition, + ui::PAGE_TRANSITION_FORM_SUBMIT) || + transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK)) { + // Creating a sub-task with navigation at current_navigation_index as + // parent. + DVLOG(1) << "Creating a sub-task with navigation_index: " + << navigation_index << " of transition: " << transition + << " under navigation_index: " << current_navigation_index_; + // Position in task_id_. + int current_navigation_position = + current_navigation_index_ - excluded_navigation_num_; + // If current/parent task is excluded, consider the new task as a root task. + if (current_navigation_position >= 0) { + CHECK_LT(current_navigation_position, + base::checked_cast<int>(task_ids_.size())); + root_navigation_index = + task_ids_[current_navigation_position].root_navigation_index; + } else { + DVLOG(1) << "Becaue parent task is excluded, consider the sub-task as a " + "root task."; + } + } else { + // Creating a root task. + // For now, we don't consider tasks cross tabs, so first navigation of the + // tab always creates a root task. + DVLOG(1) << "Creating a root task with navigation_index: " + << navigation_index << " of transition: " << transition; + } + + // In most cases navigation_index == excluded_navigation_num_ + + // task_ids_.size() if the previous navigation is end of chain, or + // navigation_index < excluded_navigation_num_ + task_ids_.size() otherwise. + // In few case navigation_index > excluded_navigation_num_ + task_ids_.size(), + // we fill task_ids_ with invalid contents. A known case is the first + // navigation after newtab. + for (int i = task_ids_.size() + excluded_navigation_num_; + i < navigation_index; i++) { + task_ids_.push_back({-1, -1}); + } + + // Erase all task ids associated with an outdated forward navigation stack. + if (navigation_index > excluded_navigation_num_) { + int new_task_id_position = navigation_index - excluded_navigation_num_; + task_ids_.erase(task_ids_.begin() + new_task_id_position, task_ids_.end()); + } else { + excluded_navigation_num_ = navigation_index; + // new task id position is 0 + task_ids_.clear(); + } + + // Exclude oldest ancestors if task number reaches the limit. + int more_tasks_number = task_ids_.size() + 1 - kMaxNumTasksPerTab; + if (more_tasks_number > 0) { + task_ids_.erase(task_ids_.begin(), task_ids_.begin() + more_tasks_number); + DVLOG(1) << "Excluding " << more_tasks_number + << " oldest ancestor(s) from navigation index " + << excluded_navigation_num_; + excluded_navigation_num_ += more_tasks_number; + } + + TaskIdAndRoot new_task = {root_navigation_index, navigation_id}; + // Add the current task at navigation_index. + task_ids_.push_back(new_task); + current_navigation_index_ = navigation_index; + return; +} + +TaskTracker::TaskTracker() {} + +TaskTracker::~TaskTracker() {} + +TabTasks* TaskTracker::GetTabTasks(SessionID::id_type tab_id) { + if (local_tab_tasks_map_.find(tab_id) == local_tab_tasks_map_.end()) { + local_tab_tasks_map_[tab_id] = base::MakeUnique<TabTasks>(); + } + return local_tab_tasks_map_[tab_id].get(); +} + +void TaskTracker::CleanTabTasks(SessionID::id_type tab_id) { + auto iter = local_tab_tasks_map_.find(tab_id); + if (iter != local_tab_tasks_map_.end()) { + local_tab_tasks_map_.erase(iter); + } +} + +} // namespace sync_sessions
diff --git a/components/sync_sessions/task_tracker.h b/components/sync_sessions/task_tracker.h new file mode 100644 index 0000000..44ee3636 --- /dev/null +++ b/components/sync_sessions/task_tracker.h
@@ -0,0 +1,102 @@ +// 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 COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_ +#define COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_ + +#include <stddef.h> + +#include <map> +#include <memory> +#include <vector> + +#include "base/time/clock.h" +#include "base/time/default_clock.h" +#include "base/time/time.h" +#include "components/sessions/core/session_id.h" +#include "components/sessions/core/session_types.h" +#include "components/sync_sessions/synced_tab_delegate.h" +#include "ui/base/page_transition_types.h" + +namespace sync_sessions { + +// Class to generate and manage task ids for navigations of a tab. For each +// current navigation of a tab, UpdateWithNavigation(int navigation_index, +// ui::PageTransition transition) +// needs to be called to update the object. +// +// TODO(shenchao): If the tab is restored, then the input navigation is not +// necessarily the first navigation in this case. Need to fix it by initalizing +// the object with restored data. +// TODO(shenchao): Support to track tasks cross tabs. +class TabTasks { + public: + TabTasks(); + virtual ~TabTasks(); + + // Gets top-down task id list of ancestors and itself for + // |navigation_index|-th navigation of the tab. + std::vector<int64_t> GetTaskIdsForNavigation(int navigation_index) const; + + int GetNavigationsCount() const; + + // Updates the current task of the tab, given current navigation index of the + // tab as |navigation_index|, and its |transition|. + // If the navigation is from going back/forward of the tab, we set its first + // visit as current task; if the navigation is new, we create a subtask of the + // previous navigation if it's linked from the previous one or a root task + // otherwise, and use |navigation_id| as new task id. + void UpdateWithNavigation(int navigation_index, + ui::PageTransition transition, + int64_t navigation_id); + + private: + FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest, LimitMaxNumberOfTasksPerTab); + + FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest, + CreateSubTaskFromExcludedAncestorTask); + + struct TaskIdAndRoot { + // Root task index in task_ids_. Negative value means it's an invalid task + // just for filling the task_ids_. + int root_navigation_index; + int64_t task_id; + }; + + // Task ids (with root task) for the navigations of the tab. The vector is + // corresponding to the sequence of navigations of the tab. + std::vector<TaskIdAndRoot> task_ids_; + // Index of current navigation in task_ids_. + int current_navigation_index_ = -1; + // Number of oldest ancestors which have been excluded from being tracked in + // task_ids_; + int excluded_navigation_num_ = 0; + + DISALLOW_COPY_AND_ASSIGN(TabTasks); +}; + +// Tracks tasks of current session. +class TaskTracker { + public: + // Constructs with a clock to get timestamp as new task ids. + TaskTracker(); + virtual ~TaskTracker(); + + // Returns a TabTasks pointer, which is owned by this object, for the tab of + // given |tab_id|. + TabTasks* GetTabTasks(SessionID::id_type tab_id); + + // Cleans tracked task ids of navigations in the tab of |tab_id|. + void CleanTabTasks(SessionID::id_type tab_id); + + private: + FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest, CleanTabTasks); + std::map<SessionID::id_type, std::unique_ptr<TabTasks>> local_tab_tasks_map_; + + DISALLOW_COPY_AND_ASSIGN(TaskTracker); +}; + +} // namespace sync_sessions + +#endif // COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_
diff --git a/components/sync_sessions/task_tracker_unittest.cc b/components/sync_sessions/task_tracker_unittest.cc new file mode 100644 index 0000000..40fd0424 --- /dev/null +++ b/components/sync_sessions/task_tracker_unittest.cc
@@ -0,0 +1,198 @@ +// 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 "components/sync_sessions/task_tracker.h" + +#include <utility> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; +using testing::SizeIs; + +namespace sync_sessions { + +namespace { +const int kTab1 = 15; +const int kTab2 = 25; +} // namespace + +TEST(TaskTrackerTest, GetTabTasks) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + ASSERT_NE(tab_tasks, nullptr); + EXPECT_EQ(task_tracker.GetTabTasks(kTab1), tab_tasks); + EXPECT_NE(task_tracker.GetTabTasks(kTab2), tab_tasks); +} + +TEST(TaskTrackerTest, CleanTabTasks) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + ASSERT_NE(tab_tasks, nullptr); + ASSERT_FALSE(task_tracker.local_tab_tasks_map_.empty()); + + task_tracker.CleanTabTasks(kTab1); + EXPECT_TRUE(task_tracker.local_tab_tasks_map_.empty()); +} + +TEST(TaskTrackerTest, UpdateTasksWithMultipleClicks) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + + tab_tasks->UpdateWithNavigation(1, ui::PageTransition::PAGE_TRANSITION_TYPED, + 100); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + + tab_tasks->UpdateWithNavigation(2, ui::PageTransition::PAGE_TRANSITION_LINK, + 200); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200)); + + tab_tasks->UpdateWithNavigation(3, ui::PageTransition::PAGE_TRANSITION_LINK, + 300); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3), + ElementsAre(100, 200, 300)); +} + +TEST(TaskTrackerTest, UpdateTasksWithMultipleClicksAndTypes) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + + tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK, 100); + tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200); + tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300); + tab_tasks->UpdateWithNavigation(4, ui::PAGE_TRANSITION_TYPED, 400); + tab_tasks->UpdateWithNavigation(5, ui::PAGE_TRANSITION_LINK, 500); + tab_tasks->UpdateWithNavigation(6, ui::PAGE_TRANSITION_TYPED, 600); + tab_tasks->UpdateWithNavigation(7, ui::PAGE_TRANSITION_LINK, 700); + + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3), + ElementsAre(100, 200, 300)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(4), ElementsAre(400)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(5), ElementsAre(400, 500)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(6), ElementsAre(600)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(7), ElementsAre(600, 700)); +} + +TEST(TaskTrackerTest, UpdateTasksWithBackforwards) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + + tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_TYPED, 100); + tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200); + tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300); + + tab_tasks->UpdateWithNavigation( + 1, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | + ui::PAGE_TRANSITION_FORWARD_BACK), + 400); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3), + ElementsAre(100, 200, 300)); + + tab_tasks->UpdateWithNavigation( + 3, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK | + ui::PAGE_TRANSITION_FORWARD_BACK), + 500); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3), + ElementsAre(100, 200, 300)); +} + +TEST(TaskTrackerTest, UpdateWithNavigationsWithBackAndForkedNavigation) { + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK, 100); + tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200); + tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300); + tab_tasks->UpdateWithNavigation( + 1, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK | + ui::PAGE_TRANSITION_FORWARD_BACK), + 400); + tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 500); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 500)); + // We don't track navigation at index 3 any more, and it's out of scope now. + EXPECT_THAT(tab_tasks->GetNavigationsCount(), 3); +} + +TEST(TaskTrackerTest, LimitMaxNumberOfTasksPerTab) { + int kMaxNumTasksPerTab = 100; + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + + // Reaching max number of tasks for a tab. + for (int i = 0; i < kMaxNumTasksPerTab; i++) { + tab_tasks->UpdateWithNavigation(i, ui::PAGE_TRANSITION_LINK, i * 100); + } + + tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab, ui::PAGE_TRANSITION_LINK, + kMaxNumTasksPerTab * 100); + + ASSERT_THAT(tab_tasks->task_ids_, SizeIs(kMaxNumTasksPerTab)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre()); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100)); + std::vector<int64_t> task_ids = + tab_tasks->GetTaskIdsForNavigation(kMaxNumTasksPerTab); + EXPECT_THAT(task_ids, SizeIs(kMaxNumTasksPerTab)); + EXPECT_EQ(task_ids[0], 100); + EXPECT_EQ(task_ids[kMaxNumTasksPerTab - 1], kMaxNumTasksPerTab * 100); + + tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab + 1, + ui::PAGE_TRANSITION_LINK, + (kMaxNumTasksPerTab + 1) * 100); + + ASSERT_THAT(tab_tasks->task_ids_, SizeIs(kMaxNumTasksPerTab)); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre()); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre()); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(200)); + task_ids = tab_tasks->GetTaskIdsForNavigation(kMaxNumTasksPerTab + 1); + EXPECT_THAT(task_ids, SizeIs(kMaxNumTasksPerTab)); + EXPECT_EQ(task_ids[0], 200); + EXPECT_EQ(task_ids[kMaxNumTasksPerTab - 1], (kMaxNumTasksPerTab + 1) * 100); +} + +TEST(TaskTrackerTest, CreateSubTaskFromExcludedAncestorTask) { + int kMaxNumTasksPerTab = 100; + TaskTracker task_tracker; + TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1); + + // Reaching max number of tasks for a tab. + for (int i = 0; i < kMaxNumTasksPerTab; i++) { + tab_tasks->UpdateWithNavigation(i, ui::PAGE_TRANSITION_LINK, i * 100); + } + + tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab, ui::PAGE_TRANSITION_LINK, + kMaxNumTasksPerTab * 100); + ASSERT_EQ(tab_tasks->excluded_navigation_num_, 1); + ASSERT_EQ(tab_tasks->current_navigation_index_, kMaxNumTasksPerTab); + + tab_tasks->UpdateWithNavigation( + 0, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK | + ui::PAGE_TRANSITION_FORWARD_BACK), + (kMaxNumTasksPerTab + 1) * 100); + ASSERT_EQ(tab_tasks->excluded_navigation_num_, 1); + ASSERT_EQ(tab_tasks->current_navigation_index_, 0); + + tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK, + (kMaxNumTasksPerTab + 2) * 100); + ASSERT_THAT(tab_tasks->task_ids_, SizeIs(1)); + ASSERT_EQ(tab_tasks->GetNavigationsCount(), 2); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre()); + EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), + ElementsAre((kMaxNumTasksPerTab + 2) * 100)); +} + +} // namespace sync_sessions
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc index ee8613adf..f585d90e1 100644 --- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc +++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -64,8 +64,8 @@ } // ContentBrowserTest - void SetUpInProcessBrowserTestFixture() override; - void TearDownInProcessBrowserTestFixture() override; + void SetUpOnMainThread() override; + void TearDownOnMainThread() override; protected: std::string GetAttr(const ui::AXNode* node, @@ -83,15 +83,14 @@ DISALLOW_COPY_AND_ASSIGN(CrossPlatformAccessibilityBrowserTest); }; -void CrossPlatformAccessibilityBrowserTest::SetUpInProcessBrowserTestFixture() { +void CrossPlatformAccessibilityBrowserTest::SetUpOnMainThread() { #if defined(OS_WIN) ui::win::CreateATLModuleIfNeeded(); com_initializer_.reset(new base::win::ScopedCOMInitializer()); #endif } -void -CrossPlatformAccessibilityBrowserTest::TearDownInProcessBrowserTestFixture() { +void CrossPlatformAccessibilityBrowserTest::TearDownOnMainThread() { #if defined(OS_WIN) com_initializer_.reset(); #endif
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc index 3192cd0d..8e3a3d8 100644 --- a/content/browser/blob_storage/chrome_blob_storage_context.cc +++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -15,6 +15,8 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner.h" #include "base/threading/sequenced_worker_pool.h" +#include "content/browser/resource_context_impl.h" +#include "content/common/resource_request_body_impl.h" #include "content/public/browser/blob_handle.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -186,4 +188,33 @@ delete this; } +storage::BlobStorageContext* GetBlobStorageContext( + ChromeBlobStorageContext* blob_storage_context) { + if (!blob_storage_context) + return NULL; + return blob_storage_context->context(); +} + +void AttachRequestBodyBlobDataHandles(ResourceRequestBodyImpl* body, + ResourceContext* resource_context) { + storage::BlobStorageContext* blob_context = GetBlobStorageContext( + GetChromeBlobStorageContextForResourceContext(resource_context)); + + DCHECK(blob_context); + for (size_t i = 0; i < body->elements()->size(); ++i) { + const ResourceRequestBodyImpl::Element& element = (*body->elements())[i]; + if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB) + continue; + std::unique_ptr<storage::BlobDataHandle> handle = + blob_context->GetBlobDataFromUUID(element.blob_uuid()); + DCHECK(handle); + if (!handle) + continue; + // Ensure the blob and any attached shareable files survive until + // upload completion. The |body| takes ownership of |handle|. + const void* key = handle.get(); + body->SetUserData(key, handle.release()); + } +} + } // namespace content
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.h b/content/browser/blob_storage/chrome_blob_storage_context.h index 4c7cfac..ad4a2a2 100644 --- a/content/browser/blob_storage/chrome_blob_storage_context.h +++ b/content/browser/blob_storage/chrome_blob_storage_context.h
@@ -29,6 +29,8 @@ class BlobHandle; class BrowserContext; struct ChromeBlobStorageContextDeleter; +class ResourceRequestBodyImpl; +class ResourceContext; // A context class that keeps track of BlobStorageController used by the chrome. // There is an instance associated with each BrowserContext. There could be @@ -82,6 +84,16 @@ } }; +// Returns the BlobStorageContext associated with the +// ChromeBlobStorageContext instance passed in. +storage::BlobStorageContext* GetBlobStorageContext( + ChromeBlobStorageContext* blob_storage_context); + +// Attaches blob data handles to the ResourceRequestBodyImpl body passed in. +// This is used for POST and PUT requests. +void AttachRequestBodyBlobDataHandles(ResourceRequestBodyImpl* body, + ResourceContext* resource_context); + } // namespace content #endif // CONTENT_BROWSER_FILEAPI_CHROME_BLOB_STORAGE_CONTEXT_H_
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 0dc52fca..5021cd5 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -217,14 +217,17 @@ #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) void SetupSandbox(const base::CommandLine& parsed_command_line) { TRACE_EVENT0("startup", "SetupSandbox"); + // RenderSandboxHostLinux needs to be initialized even if the sandbox and + // zygote are both disabled. It initializes the renderer socket. + RenderSandboxHostLinux::GetInstance()->Init(); + if (parsed_command_line.HasSwitch(switches::kNoZygote)) { CHECK(parsed_command_line.HasSwitch(switches::kNoSandbox)) << "--no-sandbox should be used together with --no--zygote"; return; } - // Tickle the sandbox host and zygote host so they fork now. - RenderSandboxHostLinux::GetInstance()->Init(); + // Tickle the zygote host so it forks now. ZygoteHostImpl::GetInstance()->Init(parsed_command_line); *GetGenericZygote() = CreateZygote(); RenderProcessHostImpl::EarlyZygoteLaunch();
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index 525d09e..1d409a8d 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc
@@ -18,9 +18,13 @@ #include "base/format_macros.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/field_trial_params.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/mock_entropy_provider.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/platform_thread.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" @@ -32,6 +36,7 @@ #include "content/browser/download/download_item_impl.h" #include "content/browser/download/download_manager_impl.h" #include "content/browser/download/download_resource_handler.h" +#include "content/browser/download/parallel_download_utils.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/download_danger_type.h" @@ -82,6 +87,9 @@ namespace { +// Default request count for parallel download tests. +constexpr int kTestRequestCount = 3; + class MockDownloadItemObserver : public DownloadItem::Observer { public: MockDownloadItemObserver() {} @@ -589,8 +597,8 @@ make_scoped_refptr(content::BrowserThread::GetBlockingPool()))); } - void SetUpCommandLine(base::CommandLine* commnad_line) override { - IsolateAllSitesForTesting(commnad_line); + void SetUpCommandLine(base::CommandLine* command_line) override { + IsolateAllSitesForTesting(command_line); } TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() { @@ -747,6 +755,45 @@ std::unique_ptr<TestShellDownloadManagerDelegate> test_delegate_; }; +// Test fixture for parallel downloading. +class ParallelDownloadTest : public DownloadContentTest { + protected: + void SetUp() override { + field_trial_list_ = base::MakeUnique<base::FieldTrialList>( + base::MakeUnique<base::MockEntropyProvider>()); + SetupConfig(); + DownloadContentTest::SetUp(); + } + + private: + // TODO(xingliu): Use this technique in parallel download unit tests to load + // the finch configuration. + void SetupConfig() { + const std::string kTrialName = "trial_name"; + const std::string kGroupName = "group_name"; + + std::map<std::string, std::string> params; + params[content::kMinSliceSizeFinchKey] = "1"; + params[content::kParallelRequestCountFinchKey] = + base::IntToString(kTestRequestCount); + params[content::kParallelRequestDelayFinchKey] = "0"; + params[content::kParallelRequestRemainingTimeFinchKey] = "0"; + + scoped_refptr<base::FieldTrial> trial = + base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); + base::AssociateFieldTrialParams(kTrialName, kGroupName, params); + std::unique_ptr<base::FeatureList> feature_list = + base::MakeUnique<base::FeatureList>(); + feature_list->RegisterFieldTrialOverride( + features::kParallelDownloading.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); + scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + } + + std::unique_ptr<base::FieldTrialList> field_trial_list_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + } // namespace IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) { @@ -2655,4 +2702,30 @@ download->GetTargetFilePath().BaseName().value().c_str()); } +IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ParallelDownloadComplete) { + EXPECT_TRUE(base::FeatureList::IsEnabled(features::kParallelDownloading)); + + TestDownloadRequestHandler request_handler; + TestDownloadRequestHandler::Parameters parameters; + parameters.etag = "ABC"; + parameters.size = 5097152; + // Only parallel download needs to specify the connection type to http 1.1, + // other tests will automatically fall back to non-parallel download even if + // the ParallelDownloading feature is enabled based on + // fieldtrial_testing_config.json. + parameters.connection_type = net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1; + request_handler.StartServing(parameters); + + DownloadItem* download = + StartDownloadAndReturnItem(shell(), request_handler.url()); + WaitForCompletion(download); + + TestDownloadRequestHandler::CompletedRequests completed_requests; + request_handler.GetCompletedRequestInfo(&completed_requests); + EXPECT_EQ(kTestRequestCount, static_cast<int>(completed_requests.size())); + + ReadAndVerifyFileContents(parameters.pattern_generator_seed, parameters.size, + download->GetTargetFilePath()); +} + } // namespace content
diff --git a/content/browser/download/download_job_factory.cc b/content/browser/download/download_job_factory.cc index a6ac607a..f170470 100644 --- a/content/browser/download/download_job_factory.cc +++ b/content/browser/download/download_job_factory.cc
@@ -78,6 +78,7 @@ } // namespace +// static std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob( DownloadItemImpl* download_item, std::unique_ptr<DownloadRequestHandleInterface> req_handle,
diff --git a/content/browser/download/parallel_download_utils.cc b/content/browser/download/parallel_download_utils.cc index 1e3d900b..49fc009 100644 --- a/content/browser/download/parallel_download_utils.cc +++ b/content/browser/download/parallel_download_utils.cc
@@ -14,30 +14,13 @@ namespace { -// Finch parameter key value for minimum slice size in bytes to use parallel -// download. -const char kMinSliceSizeFinchKey[] = "min_slice_size"; - // Default value for |kMinSliceSizeFinchKey|, when no parameter is specified. const int64_t kMinSliceSizeParallelDownload = 2097152; -// Finch parameter key value for number of parallel requests in a parallel -// download, including the original request. -const char kParallelRequestCountFinchKey[] = "request_count"; - // Default value for |kParallelRequestCountFinchKey|, when no parameter is // specified. const int kParallelRequestCount = 2; -// Finch parameter key value for the delay time in milliseconds to send -// parallel requests after response of the original request is handled. -const char kParallelRequestDelayFinchKey[] = "parallel_request_delay"; - -// Finch parameter key value for the remaining time in seconds that is required -// to send parallel requests. -const char kParallelRequestRemainingTimeFinchKey[] = - "parallel_request_remaining_time"; - // The default remaining download time in seconds required for parallel request // creation. const int kDefaultRemainingTimeInSeconds = 10;
diff --git a/content/browser/download/parallel_download_utils.h b/content/browser/download/parallel_download_utils.h index c6031f5..fcf7f39b 100644 --- a/content/browser/download/parallel_download_utils.h +++ b/content/browser/download/parallel_download_utils.h
@@ -13,6 +13,23 @@ namespace content { +// Finch parameter key value for minimum slice size in bytes to use parallel +// download. +constexpr char kMinSliceSizeFinchKey[] = "min_slice_size"; + +// Finch parameter key value for number of parallel requests in a parallel +// download, including the original request. +constexpr char kParallelRequestCountFinchKey[] = "request_count"; + +// Finch parameter key value for the delay time in milliseconds to send +// parallel requests after response of the original request is handled. +constexpr char kParallelRequestDelayFinchKey[] = "parallel_request_delay"; + +// Finch parameter key value for the remaining time in seconds that is required +// to send parallel requests. +constexpr char kParallelRequestRemainingTimeFinchKey[] = + "parallel_request_remaining_time"; + // Chunks the content that starts from |current_offset|, into at most // std::max(|request_count|, 1) smaller slices. // Each slice contains at least |min_slice_size| bytes unless |total_length|
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h index 5a1f906..9982cea4 100644 --- a/content/browser/frame_host/navigator.h +++ b/content/browser/frame_host/navigator.h
@@ -121,6 +121,7 @@ const std::string& extra_headers, const Referrer& referrer, WindowOpenDisposition disposition, + bool force_new_process_for_new_contents, bool should_replace_current_entry, bool user_gesture) {}
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index 6dd1df2..e1a5cc6 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -732,6 +732,7 @@ const std::string& extra_headers, const Referrer& referrer, WindowOpenDisposition disposition, + bool force_new_process_for_new_contents, bool should_replace_current_entry, bool user_gesture) { // Note: This can be called for subframes (even when OOPIFs are not possible) @@ -774,6 +775,8 @@ OpenURLParams params(dest_url, referrer, frame_tree_node_id, disposition, ui::PAGE_TRANSITION_LINK, true /* is_renderer_initiated */); + params.force_new_process_for_new_contents = + force_new_process_for_new_contents; params.uses_post = uses_post; params.post_data = body; params.extra_headers = extra_headers;
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h index e59fa4e..997ddcbf 100644 --- a/content/browser/frame_host/navigator_impl.h +++ b/content/browser/frame_host/navigator_impl.h
@@ -71,6 +71,7 @@ const std::string& extra_headers, const Referrer& referrer, WindowOpenDisposition disposition, + bool force_new_process_for_new_contents, bool should_replace_current_entry, bool user_gesture) override; void RequestTransferURL(RenderFrameHostImpl* render_frame_host,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index a64bf5be6..b730c3c 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1172,10 +1172,22 @@ TRACE_EVENT1("navigation", "RenderFrameHostImpl::OpenURL", "url", validated_url.possibly_invalid_spec()); + // When |params.disposition| asks OpenURL to create new contents, it always + // happens because of an explicit user request for new content creation (i.e. + // opening a link using ctrl-click or middle click). In such cases, the new + // content should be created in a new renderer to break opener relationship + // (see https://crbug.com/658386) and to conserve memory per renderer (see + // https://crbug.com/23815). Note that new content creation that wasn't + // explicitly requested by the user (i.e. left-clicking a link with + // target=_blank) goes through a different code path (through + // WebViewClient::CreateView). + bool kForceNewProcessForNewContents = true; + frame_tree_node_->navigator()->RequestOpenURL( this, validated_url, params.uses_post, params.resource_request_body, params.extra_headers, params.referrer, params.disposition, - params.should_replace_current_entry, params.user_gesture); + kForceNewProcessForNewContents, params.should_replace_current_entry, + params.user_gesture); } void RenderFrameHostImpl::OnCancelInitialHistoryLoad() {
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc index 5e16a9328..5ff9458 100644 --- a/content/browser/loader/navigation_url_loader_network_service.cc +++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -4,7 +4,10 @@ #include "content/browser/loader/navigation_url_loader_network_service.h" +#include "base/bind.h" +#include "base/bind_helpers.h" #include "base/memory/ptr_util.h" +#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/frame_host/navigation_request_info.h" #include "content/browser/loader/navigation_resource_handler.h" #include "content/browser/loader/navigation_resource_throttle.h" @@ -15,13 +18,32 @@ #include "content/public/browser/navigation_ui_data.h" #include "content/public/browser/ssl_status.h" #include "content/public/browser/stream_handle.h" +#include "content/public/common/referrer.h" #include "content/public/common/service_manager_connection.h" #include "content/public/common/service_names.mojom.h" +#include "net/base/load_flags.h" #include "net/url_request/url_request_context.h" #include "services/service_manager/public/cpp/connector.h" namespace content { +// This function is called on the IO thread for POST/PUT requests for +// attaching blob information to the request body. +void HandleRequestsWithBody( + std::unique_ptr<ResourceRequest> request, + ResourceContext* resource_context, + base::WeakPtr<NavigationURLLoaderNetworkService> url_loader) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(request->request_body.get()); + + AttachRequestBodyBlobDataHandles(request->request_body.get(), + resource_context); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NavigationURLLoaderNetworkService::StartURLRequest, + url_loader, base::Passed(&request))); +} + NavigationURLLoaderNetworkService::NavigationURLLoaderNetworkService( ResourceContext* resource_context, StoragePartition* storage_partition, @@ -30,8 +52,9 @@ ServiceWorkerNavigationHandle* service_worker_handle, AppCacheNavigationHandle* appcache_handle, NavigationURLLoaderDelegate* delegate) - : delegate_(delegate), binding_(this) { + : delegate_(delegate), binding_(this), weak_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + // TODO(scottmg): Maybe some of this setup should be done only once, instead // of every time. ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface( @@ -39,18 +62,46 @@ // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here. auto new_request = base::MakeUnique<ResourceRequest>(); - new_request->method = "GET"; + + new_request->method = request_info->common_params.method; new_request->url = request_info->common_params.url; new_request->first_party_for_cookies = request_info->first_party_for_cookies; new_request->priority = net::HIGHEST; - mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass; - binding_.Bind(&url_loader_client_ptr_to_pass); + // The code below to set fields like request_initiator, referrer, etc has + // been copied from ResourceDispatcherHostImpl. We did not refactor the + // common code into a function, because RDHI uses accessor functions on the + // URLRequest class to set these fields. whereas we use ResourceRequest here. + new_request->request_initiator = request_info->begin_params.initiator_origin; + new_request->referrer = request_info->common_params.referrer.url; + new_request->referrer_policy = request_info->common_params.referrer.policy; + new_request->headers = request_info->begin_params.headers; - url_loader_factory_->CreateLoaderAndStart( - mojo::MakeRequest(&url_loader_associated_ptr_), 0 /* routing_id? */, - 0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo, *new_request, - std::move(url_loader_client_ptr_to_pass)); + int load_flags = request_info->begin_params.load_flags; + load_flags |= net::LOAD_VERIFY_EV_CERT; + if (request_info->is_main_frame) + load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED; + + // Sync loads should have maximum priority and should be the only + // requests that have the ignore limits flag set. + DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS)); + + new_request->load_flags = load_flags; + + new_request->request_body = request_info->common_params.post_data.get(); + if (new_request->request_body.get()) { + // The request body may need blob handles to be added to it. This + // functionality has to be invoked on the IO thread. + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&HandleRequestsWithBody, + base::Passed(&new_request), + resource_context, + weak_factory_.GetWeakPtr())); + return; + } + + StartURLRequest(std::move(new_request)); } NavigationURLLoaderNetworkService::~NavigationURLLoaderNetworkService() {} @@ -118,4 +169,17 @@ } } +void NavigationURLLoaderNetworkService::StartURLRequest( + std::unique_ptr<ResourceRequest> request) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass; + binding_.Bind(&url_loader_client_ptr_to_pass); + + url_loader_factory_->CreateLoaderAndStart( + mojo::MakeRequest(&url_loader_associated_ptr_), 0 /* routing_id? */, + 0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo, *request, + std::move(url_loader_client_ptr_to_pass)); +} + } // namespace content
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h index bb574b1..a60b276 100644 --- a/content/browser/loader/navigation_url_loader_network_service.h +++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -6,6 +6,7 @@ #define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_NETWORK_SERVICE_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "content/browser/loader/navigation_url_loader.h" #include "content/common/url_loader.mojom.h" #include "content/common/url_loader_factory.mojom.h" @@ -20,6 +21,7 @@ namespace content { class ResourceContext; +class NavigationPostDataHandler; // This is an implementation of NavigationURLLoader used when // --enable-network-service is used. @@ -58,6 +60,9 @@ void OnComplete( const ResourceRequestCompletionStatus& completion_status) override; + // Initiates the request. + void StartURLRequest(std::unique_ptr<ResourceRequest> request); + private: void ConnectURLLoaderFactory( std::unique_ptr<service_manager::Connector> connector); @@ -70,6 +75,8 @@ scoped_refptr<ResourceResponse> response_; SSLStatus ssl_status_; + base::WeakPtrFactory<NavigationURLLoaderNetworkService> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderNetworkService); };
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index a9c9157..7271a3a 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -137,7 +137,7 @@ const int kUpdateLoadStatesIntervalMsec = 250; // Maximum byte "cost" of all the outstanding requests for a renderer. -// See delcaration of |max_outstanding_requests_cost_per_process_| for details. +// See declaration of |max_outstanding_requests_cost_per_process_| for details. // This bound is 25MB, which allows for around 6000 outstanding requests. const int kMaxOutstandingRequestsCostPerProcess = 26214400; @@ -265,33 +265,6 @@ return sct_status.status == net::ct::SCT_STATUS_OK; } -storage::BlobStorageContext* GetBlobStorageContext( - ChromeBlobStorageContext* blob_storage_context) { - if (!blob_storage_context) - return NULL; - return blob_storage_context->context(); -} - -void AttachRequestBodyBlobDataHandles( - ResourceRequestBodyImpl* body, - storage::BlobStorageContext* blob_context) { - DCHECK(blob_context); - for (size_t i = 0; i < body->elements()->size(); ++i) { - const ResourceRequestBodyImpl::Element& element = (*body->elements())[i]; - if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB) - continue; - std::unique_ptr<storage::BlobDataHandle> handle = - blob_context->GetBlobDataFromUUID(element.blob_uuid()); - DCHECK(handle); - if (!handle) - continue; - // Ensure the blob and any attached shareable files survive until - // upload completion. The |body| takes ownership of |handle|. - const void* key = handle.get(); - body->SetUserData(key, handle.release()); - } -} - // Returns the PreviewsState after requesting it from the delegate. The // PreviewsState is a bitmask of potentially several Previews optimizations. PreviewsState GetPreviewsState(PreviewsState previews_state, @@ -350,6 +323,8 @@ max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), max_outstanding_requests_cost_per_process_( kMaxOutstandingRequestsCostPerProcess), + largest_outstanding_request_count_seen_(0), + largest_outstanding_request_per_process_count_seen_(0), delegate_(nullptr), loader_delegate_(nullptr), allow_cross_origin_auth_prompt_(false), @@ -1298,9 +1273,8 @@ // Attaches the BlobDataHandles to request_body not to free the blobs and // any attached shareable files until upload completion. These data will // be used in UploadDataStream and ServiceWorkerURLRequestJob. - AttachRequestBodyBlobDataHandles( - request_data.request_body.get(), - blob_context); + AttachRequestBodyBlobDataHandles(request_data.request_body.get(), + resource_context); } new_request->set_upload(UploadDataStreamBuilder::Build( request_data.request_body.get(), blob_context, @@ -1904,6 +1878,20 @@ DCHECK_GE(stats.num_requests, 0); UpdateOutstandingRequestsStats(*info, stats); + if (num_in_flight_requests_ > largest_outstanding_request_count_seen_) { + largest_outstanding_request_count_seen_ = num_in_flight_requests_; + UMA_HISTOGRAM_COUNTS_1M( + "Net.ResourceDispatcherHost.OutstandingRequests.Total", + largest_outstanding_request_count_seen_); + } + + if (stats.num_requests > largest_outstanding_request_count_seen_) { + largest_outstanding_request_per_process_count_seen_ = stats.num_requests; + UMA_HISTOGRAM_COUNTS_1M( + "Net.ResourceDispatcherHost.OutstandingRequests.PerProcess", + largest_outstanding_request_per_process_count_seen_); + } + return stats; } @@ -2009,7 +1997,7 @@ // Resolve elements from request_body and prepare upload data. ResourceRequestBodyImpl* body = info.common_params.post_data.get(); if (body) { - AttachRequestBodyBlobDataHandles(body, blob_context); + AttachRequestBodyBlobDataHandles(body, resource_context); // TODO(davidben): The FileSystemContext is null here. In the case where // another renderer requested this navigation, this should be the same // FileSystemContext passed into ShouldServiceRequest.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 4821073e..3667199 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -742,6 +742,12 @@ // kAvgBytesPerOutstandingRequest) int max_outstanding_requests_cost_per_process_; + // Largest number of outstanding requests seen so far across all processes. + int largest_outstanding_request_count_seen_; + + // Largest number of outstanding requests seen so far in any single process. + int largest_outstanding_request_per_process_count_seen_; + // Time of the last user gesture. Stored so that we can add a load // flag to requests occurring soon after a gesture to indicate they // may be because of explicit user action.
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 6ae8ed6..7eed4ac 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -92,7 +92,7 @@ wc->GetFrameTree()->root()->navigator()->RequestOpenURL( wc->GetFrameTree()->root()->current_frame_host(), extension_url, false, nullptr, std::string(), Referrer(), WindowOpenDisposition::CURRENT_TAB, - false, true); + false, false, true); // Since the navigation above requires a cross-process swap, there will be a // speculative/pending RenderFrameHost. Ensure it exists and is in a different
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc index d51fea6..73c4cc0 100644 --- a/content/browser/speech/speech_recognition_browsertest.cc +++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -111,15 +111,13 @@ protected: // ContentBrowserTest methods. - void SetUpInProcessBrowserTestFixture() override { + void SetUpOnMainThread() override { test_audio_input_controller_factory_.set_delegate(this); media::AudioInputController::set_factory_for_testing( &test_audio_input_controller_factory_); mock_streaming_server_.reset(new MockGoogleStreamingServer(this)); streaming_server_state_ = kIdle; - } - void SetUpOnMainThread() override { ASSERT_TRUE(SpeechRecognitionManagerImpl::GetInstance()); media::AudioManager::StartHangMonitorIfNeeded( BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)); @@ -138,9 +136,7 @@ // Deleting AudioManager on audio thread, audio_system_.reset(); audio_manager_.reset(); - } - void TearDownInProcessBrowserTestFixture() override { test_audio_input_controller_factory_.set_delegate(nullptr); mock_streaming_server_.reset(); }
diff --git a/content/public/browser/page_navigator.cc b/content/public/browser/page_navigator.cc index cb7da03..de8d88e 100644 --- a/content/public/browser/page_navigator.cc +++ b/content/public/browser/page_navigator.cc
@@ -16,6 +16,7 @@ uses_post(false), frame_tree_node_id(-1), disposition(disposition), + force_new_process_for_new_contents(false), transition(transition), is_renderer_initiated(is_renderer_initiated), should_replace_current_entry(false), @@ -33,6 +34,7 @@ uses_post(false), frame_tree_node_id(-1), disposition(disposition), + force_new_process_for_new_contents(false), transition(transition), is_renderer_initiated(is_renderer_initiated), should_replace_current_entry(false), @@ -50,6 +52,7 @@ uses_post(false), frame_tree_node_id(frame_tree_node_id), disposition(disposition), + force_new_process_for_new_contents(false), transition(transition), is_renderer_initiated(is_renderer_initiated), should_replace_current_entry(false), @@ -60,6 +63,7 @@ : uses_post(false), frame_tree_node_id(-1), disposition(WindowOpenDisposition::UNKNOWN), + force_new_process_for_new_contents(false), transition(ui::PAGE_TRANSITION_LINK), is_renderer_initiated(false), should_replace_current_entry(false),
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h index eb9e6a83..166a0d51 100644 --- a/content/public/browser/page_navigator.h +++ b/content/public/browser/page_navigator.h
@@ -82,6 +82,12 @@ // The disposition requested by the navigation source. WindowOpenDisposition disposition; + // Controls creation of new web contents (in case |disposition| asks for a new + // tab or window). If |force_new_process_for_new_contents| is true, then we + // try to put the new contents in a new renderer, even if they are same-site + // as |source_site_instance| (this is subject to renderer process limits). + bool force_new_process_for_new_contents; + // The transition type of navigation. ui::PageTransition transition;
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc index 180f37f..d7d05a85 100644 --- a/content/public/test/test_download_request_handler.cc +++ b/content/public/test/test_download_request_handler.cc
@@ -412,6 +412,7 @@ HeadersFromString(base::StringPrintf("HTTP/1.1 200 Success\r\n" "Content-Length: %" PRId64 "\r\n", parameters_->size)); + response_info_.connection_info = parameters_->connection_type; AddCommonEntityHeaders(); NotifyHeadersCompleteAndPrepareToRead(); return; @@ -454,6 +455,7 @@ "Content-Length: %" PRId64 "\r\n", requested_range_begin_, requested_range_end_, parameters_->size, (requested_range_end_ - requested_range_begin_) + 1)); + response_info_.connection_info = parameters_->connection_type; AddCommonEntityHeaders(); NotifyHeadersCompleteAndPrepareToRead(); return true; @@ -585,7 +587,9 @@ content_type("application/octet-stream"), size(102400), pattern_generator_seed(1), - support_byte_ranges(true) {} + support_byte_ranges(true), + connection_type( + net::HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_UNKNOWN) {} // Copy and move constructors / assignment operators are all defaults. TestDownloadRequestHandler::Parameters::Parameters(const Parameters&) = default; @@ -599,6 +603,7 @@ size(that.size), pattern_generator_seed(that.pattern_generator_seed), support_byte_ranges(that.support_byte_ranges), + connection_type(that.connection_type), on_start_handler(that.on_start_handler), injected_errors(std::move(that.injected_errors)) {}
diff --git a/content/public/test/test_download_request_handler.h b/content/public/test/test_download_request_handler.h index 4daff5c4..629d8d61 100644 --- a/content/public/test/test_download_request_handler.h +++ b/content/public/test/test_download_request_handler.h
@@ -147,6 +147,9 @@ // If true, the response contains a 'Accept-Ranges: bytes' header. bool support_byte_ranges; + // The connection type in the response. + net::HttpResponseInfo::ConnectionInfo connection_type; + // If on_start_handler is valid, it will be invoked when a new request is // received. See details about the OnStartHandler above. OnStartHandler on_start_handler;
diff --git a/content/renderer/media_recorder/media_recorder_handler.cc b/content/renderer/media_recorder/media_recorder_handler.cc index 13986893..16b0bb1 100644 --- a/content/renderer/media_recorder/media_recorder_handler.cc +++ b/content/renderer/media_recorder/media_recorder_handler.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" +#include "content/child/scoped_web_callbacks.h" #include "content/renderer/media/media_stream_audio_track.h" #include "content/renderer/media/media_stream_track.h" #include "content/renderer/media/webrtc_uma_histograms.h" @@ -25,6 +26,7 @@ #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" #include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/modules/media_capabilities/WebMediaConfiguration.h" using base::TimeDelta; using base::TimeTicks; @@ -32,6 +34,8 @@ namespace content { +using blink::WebMediaCapabilitiesQueryCallbacks; + namespace { media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) { @@ -51,6 +55,11 @@ return media::kUnknownVideoCodec; } +void OnEncodingInfoError( + std::unique_ptr<WebMediaCapabilitiesQueryCallbacks> callbacks) { + callbacks->OnError(); +} + } // anonymous namespace MediaRecorderHandler::MediaRecorderHandler() @@ -267,6 +276,54 @@ webm_muxer_->Resume(); } +void MediaRecorderHandler::EncodingInfo( + const blink::WebMediaConfiguration& configuration, + std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> callbacks) { + DCHECK(main_render_thread_checker_.CalledOnValidThread()); + DCHECK(configuration.video_configuration || + configuration.audio_configuration); + + ScopedWebCallbacks<WebMediaCapabilitiesQueryCallbacks> scoped_callbacks = + make_scoped_web_callbacks(callbacks.release(), + base::Bind(&OnEncodingInfoError)); + + std::unique_ptr<blink::WebMediaCapabilitiesInfo> info( + new blink::WebMediaCapabilitiesInfo()); + + // TODO(mcasas): Support the case when both video and audio configurations are + // specified: https://crbug.com/709181. + std::string content_type; + if (configuration.video_configuration) + content_type = configuration.video_configuration->content_type.Ascii(); + else + content_type = configuration.audio_configuration->content_type.Ascii(); + + // |content_type| should be of the form "bla;codecs=foo", where "bla" is the + // type and "codecs=foo" is the parameter ("foo" is the parameter value), see + // RFC 2231 [1]. CanSupportMimeType() operates on type and parameter value. + // [1] https://tools.ietf.org/html/rfc2231 + base::StringTokenizer mime_tokenizer(content_type, ";"); + blink::WebString web_type; + blink::WebString web_codecs; + if (mime_tokenizer.GetNext()) + web_type = blink::WebString::FromASCII(mime_tokenizer.token()); + if (mime_tokenizer.GetNext()) { + const std::string parameters = mime_tokenizer.token(); + base::StringTokenizer parameter_tokenizer(parameters, "="); + if (parameter_tokenizer.GetNext() && + base::ToLowerASCII(parameter_tokenizer.token()) == "codecs" && + parameter_tokenizer.GetNext()) { + web_codecs = blink::WebString::FromASCII(parameter_tokenizer.token()); + } + } + + info->supported = CanSupportMimeType(web_type, web_codecs); + DVLOG(1) << "type: " << web_type.Ascii() << ", params:" << web_codecs.Ascii() + << " is" << (info->supported ? " supported" : " NOT supported"); + + scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info)); +} + void MediaRecorderHandler::OnEncodedVideo( const media::WebmMuxer::VideoParameters& params, std::unique_ptr<std::string> encoded_data,
diff --git a/content/renderer/media_recorder/media_recorder_handler.h b/content/renderer/media_recorder/media_recorder_handler.h index f7d7f64..d9affd90e 100644 --- a/content/renderer/media_recorder/media_recorder_handler.h +++ b/content/renderer/media_recorder/media_recorder_handler.h
@@ -61,6 +61,9 @@ void Stop() override; void Pause() override; void Resume() override; + void EncodingInfo( + const blink::WebMediaConfiguration& configuration, + std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> cb) override; private: friend class MediaRecorderHandlerTest;
diff --git a/content/zygote/zygote_browsertest.cc b/content/zygote/zygote_browsertest.cc index 4122bb79..5376445f 100644 --- a/content/zygote/zygote_browsertest.cc +++ b/content/zygote/zygote_browsertest.cc
@@ -5,7 +5,9 @@ #include <string> #include <vector> +#include "base/command_line.h" #include "base/strings/string_split.h" +#include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" @@ -38,4 +40,29 @@ EXPECT_TRUE(parts[2].empty()); } +class LinuxZygoteDisabledBrowserTest : public ContentBrowserTest { + public: + LinuxZygoteDisabledBrowserTest() {} + ~LinuxZygoteDisabledBrowserTest() override {} + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + ContentBrowserTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kNoZygote); + command_line->AppendSwitch(switches::kNoSandbox); + } + + private: + DISALLOW_COPY_AND_ASSIGN(LinuxZygoteDisabledBrowserTest); +}; + +// https://crbug.com/712779 +#if !defined(THREAD_SANITIZER) +// Test that the renderer doesn't crash during launch if zygote is disabled. +IN_PROC_BROWSER_TEST_F(LinuxZygoteDisabledBrowserTest, + NoCrashWhenZygoteDisabled) { + NavigateToURL(shell(), GURL("data:text/html,start page")); +} +#endif + } // namespace content
diff --git a/extensions/browser/api/serial/serial_apitest.cc b/extensions/browser/api/serial/serial_apitest.cc index eef6645..37567658e 100644 --- a/extensions/browser/api/serial/serial_apitest.cc +++ b/extensions/browser/api/serial/serial_apitest.cc
@@ -14,6 +14,7 @@ #include "extensions/browser/api/serial/serial_api.h" #include "extensions/browser/api/serial/serial_connection.h" #include "extensions/browser/extension_function.h" +#include "extensions/browser/extension_function_registry.h" #include "extensions/common/api/serial.h" #include "extensions/common/switches.h" #include "extensions/test/result_catcher.h" @@ -122,6 +123,12 @@ return new FakeSerialConnectFunction(); } +bool OverrideFunction(const std::string& name, + ExtensionFunctionFactory factory) { + return ExtensionFunctionRegistry::GetInstance()->OverrideFunctionForTesting( + name, factory); +} + } // namespace // Disable SIMULATE_SERIAL_PORTS only if all the following are true: @@ -149,10 +156,10 @@ catcher.RestrictToBrowserContext(browser()->profile()); #if SIMULATE_SERIAL_PORTS - ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( - "serial.getDevices", FakeSerialGetDevicesFunctionFactory)); - ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( - "serial.connect", FakeSerialConnectFunctionFactory)); + ASSERT_TRUE(OverrideFunction("serial.getDevices", + FakeSerialGetDevicesFunctionFactory)); + ASSERT_TRUE( + OverrideFunction("serial.connect", FakeSerialConnectFunctionFactory)); #endif ASSERT_TRUE(RunExtensionTest("serial/api")) << message_;
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index 97befcd8..a2ec0ef04 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -272,12 +272,6 @@ return GetAssociatedWebContents(); } -bool ExtensionFunctionDispatcher::OverrideFunction( - const std::string& name, ExtensionFunctionFactory factory) { - return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name, - factory); -} - // static void ExtensionFunctionDispatcher::DispatchOnIOThread( InfoMap* extension_info_map,
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h index 9aa833f4..073ca0e 100644 --- a/extensions/browser/extension_function_dispatcher.h +++ b/extensions/browser/extension_function_dispatcher.h
@@ -70,11 +70,6 @@ virtual ~Delegate() {} }; - // Override a previously registered function. Returns true if successful, - // false if no such function was registered. - static bool OverrideFunction(const std::string& name, - ExtensionFunctionFactory factory); - // Dispatches an IO-thread extension function. Only used for specific // functions that must be handled on the IO-thread. static void DispatchOnIOThread(
diff --git a/extensions/browser/extension_function_registry.cc b/extensions/browser/extension_function_registry.cc index 75114e4..714739d 100644 --- a/extensions/browser/extension_function_registry.cc +++ b/extensions/browser/extension_function_registry.cc
@@ -23,7 +23,7 @@ ExtensionFunctionRegistry::~ExtensionFunctionRegistry() {} -bool ExtensionFunctionRegistry::OverrideFunction( +bool ExtensionFunctionRegistry::OverrideFunctionForTesting( const std::string& name, ExtensionFunctionFactory factory) { FactoryMap::iterator iter = factories_.find(name);
diff --git a/extensions/browser/extension_function_registry.h b/extensions/browser/extension_function_registry.h index 128f5d0..4904036 100644 --- a/extensions/browser/extension_function_registry.h +++ b/extensions/browser/extension_function_registry.h
@@ -46,10 +46,10 @@ explicit ExtensionFunctionRegistry(); virtual ~ExtensionFunctionRegistry(); - // Allows overriding of specific functions (e.g. for testing). Functions - // must be previously registered. Returns true if successful. - bool OverrideFunction(const std::string& name, - ExtensionFunctionFactory factory); + // Allows overriding of specific functions for testing. Functions must be + // previously registered. Returns true if successful. + bool OverrideFunctionForTesting(const std::string& name, + ExtensionFunctionFactory factory); // Factory method for the ExtensionFunction registered as 'name'. ExtensionFunction* NewFunction(const std::string& name);
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index d9b33a7..ad8b044e 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -5042,19 +5042,19 @@ [self registerLoadRequest:navigationURL referrer:self.currentNavItemReferrer transition:self.currentTransition]; + WKNavigation* navigation = nil; if (navigationURL == net::GURLWithNSURL([_webView URL])) { - [_navigationStates setState:web::WKNavigationState::REQUESTED - forNavigation:[_webView reload]]; + navigation = [_webView reload]; } else { // |didCommitNavigation:| may not be called for fast navigation, so update // the navigation type now as it is already known. holder->set_navigation_type(WKNavigationTypeBackForward); - WKNavigation* navigation = + navigation = [_webView goToBackForwardListItem:holder->back_forward_list_item()]; - [_navigationStates setState:web::WKNavigationState::REQUESTED - forNavigation:navigation]; [self reportBackForwardNavigationTypeForFastNavigation:YES]; } + [_navigationStates setState:web::WKNavigationState::REQUESTED + forNavigation:navigation]; }; // If the request is not a form submission or resubmission, or the user
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc index 135d4e3..d7a3865 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -798,7 +798,7 @@ bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() { // The device may exist if the last state was a config change. - if (d3d11_device_.Get()) + if (D3D11Device()) return true; HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_, d3d11_device_manager_.Receive()); @@ -811,8 +811,9 @@ RETURN_ON_FAILURE(angle_device_.Get(), "Failed to get d3d11 device", false); using_angle_device_ = true; - d3d11_device_ = angle_device_; - } else { + } + + if (use_fp16_ || !share_nv12_textures_) { // This array defines the set of DirectX hardware feature levels we support. // The ordering MUST be preserved. All applications are assumed to support // 9.1 unless otherwise stated by the application. @@ -855,7 +856,7 @@ } D3D11_FEATURE_DATA_D3D11_OPTIONS options; - hr = d3d11_device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, + hr = D3D11Device()->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); RETURN_ON_HR_FAILURE(hr, "Failed to retrieve D3D11 options", false); @@ -866,14 +867,14 @@ UINT nv12_format_support = 0; hr = - d3d11_device_->CheckFormatSupport(DXGI_FORMAT_NV12, &nv12_format_support); + D3D11Device()->CheckFormatSupport(DXGI_FORMAT_NV12, &nv12_format_support); RETURN_ON_HR_FAILURE(hr, "Failed to check NV12 format support", false); if (!(nv12_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT)) copy_nv12_textures_ = false; UINT fp16_format_support = 0; - hr = d3d11_device_->CheckFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT, + hr = D3D11Device()->CheckFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT, &fp16_format_support); if (FAILED(hr) || !(fp16_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT)) @@ -883,18 +884,18 @@ // context are synchronized across threads. We have multiple threads // accessing the context, the media foundation decoder threads and the // decoder thread via the video format conversion transform. - hr = multi_threaded_.QueryFrom(d3d11_device_.Get()); + hr = multi_threaded_.QueryFrom(D3D11Device()); RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); multi_threaded_->SetMultithreadProtected(TRUE); - hr = d3d11_device_manager_->ResetDevice(d3d11_device_.Get(), + hr = d3d11_device_manager_->ResetDevice(D3D11Device(), dx11_dev_manager_reset_token_); RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); D3D11_QUERY_DESC query_desc; query_desc.Query = D3D11_QUERY_EVENT; query_desc.MiscFlags = 0; - hr = d3d11_device_->CreateQuery(&query_desc, d3d11_query_.Receive()); + hr = D3D11Device()->CreateQuery(&query_desc, d3d11_query_.Receive()); RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false); return true; @@ -1759,8 +1760,8 @@ (state == kNormal || state == kFlushing || state == kStopped), "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE, ); - if (d3d11_device_) - g_last_device_removed_reason = d3d11_device_->GetDeviceRemovedReason(); + if (D3D11Device()) + g_last_device_removed_reason = D3D11Device()->GetDeviceRemovedReason(); MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; DWORD status = 0; @@ -2992,4 +2993,8 @@ return provide_nv12_textures ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; } +ID3D11Device* DXVAVideoDecodeAccelerator::D3D11Device() const { + return share_nv12_textures_ ? angle_device_.Get() : d3d11_device_.Get(); +} + } // namespace media
diff --git a/media/gpu/dxva_video_decode_accelerator_win.h b/media/gpu/dxva_video_decode_accelerator_win.h index 6f45519..1e46411 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.h +++ b/media/gpu/dxva_video_decode_accelerator_win.h
@@ -374,6 +374,8 @@ uint32_t GetTextureTarget() const; + ID3D11Device* D3D11Device() const; + // To expose client callbacks from VideoDecodeAccelerator. VideoDecodeAccelerator::Client* client_;
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index 33ae123..bf7b29e9 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -4,10 +4,10 @@ #include "net/ftp/ftp_network_transaction.h" -#include "build/build_config.h" +#include <deque> -#include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -65,6 +65,7 @@ data_type_('I') { Init(); } + ~FtpSocketDataProvider() override {} // SocketDataProvider implementation. MockRead OnRead() override { @@ -244,8 +245,8 @@ class FtpSocketDataProviderDirectoryListing : public FtpSocketDataProvider { public: - FtpSocketDataProviderDirectoryListing() { - } + FtpSocketDataProviderDirectoryListing() {} + ~FtpSocketDataProviderDirectoryListing() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -271,8 +272,8 @@ class FtpSocketDataProviderDirectoryListingWithPasvFallback : public FtpSocketDataProviderDirectoryListing { public: - FtpSocketDataProviderDirectoryListingWithPasvFallback() { - } + FtpSocketDataProviderDirectoryListingWithPasvFallback() {} + ~FtpSocketDataProviderDirectoryListingWithPasvFallback() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -294,31 +295,10 @@ FtpSocketDataProviderDirectoryListingWithPasvFallback); }; -class FtpSocketDataProviderDirectoryListingZeroSize - : public FtpSocketDataProviderDirectoryListing { - public: - FtpSocketDataProviderDirectoryListingZeroSize() { - } - - MockWriteResult OnWrite(const std::string& data) override { - if (InjectFault()) - return MockWriteResult(ASYNC, data.length()); - switch (state()) { - case PRE_SIZE: - return Verify("SIZE /\r\n", data, PRE_CWD, "213 0\r\n"); - default: - return FtpSocketDataProviderDirectoryListing::OnWrite(data); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderDirectoryListingZeroSize); -}; - class FtpSocketDataProviderVMSDirectoryListing : public FtpSocketDataProvider { public: - FtpSocketDataProviderVMSDirectoryListing() { - } + FtpSocketDataProviderVMSDirectoryListing() {} + ~FtpSocketDataProviderVMSDirectoryListing() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -352,8 +332,8 @@ class FtpSocketDataProviderVMSDirectoryListingRootDirectory : public FtpSocketDataProvider { public: - FtpSocketDataProviderVMSDirectoryListingRootDirectory() { - } + FtpSocketDataProviderVMSDirectoryListingRootDirectory() {} + ~FtpSocketDataProviderVMSDirectoryListingRootDirectory() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -388,8 +368,8 @@ class FtpSocketDataProviderFileDownloadWithFileTypecode : public FtpSocketDataProvider { public: - FtpSocketDataProviderFileDownloadWithFileTypecode() { - } + FtpSocketDataProviderFileDownloadWithFileTypecode() {} + ~FtpSocketDataProviderFileDownloadWithFileTypecode() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -411,8 +391,8 @@ class FtpSocketDataProviderFileDownload : public FtpSocketDataProvider { public: - FtpSocketDataProviderFileDownload() { - } + FtpSocketDataProviderFileDownload() {} + ~FtpSocketDataProviderFileDownload() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -439,6 +419,7 @@ : public FtpSocketDataProvider { public: FtpSocketDataProviderPathSeparatorsNotUnescaped() {} + ~FtpSocketDataProviderPathSeparatorsNotUnescaped() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -465,8 +446,8 @@ class FtpSocketDataProviderFileNotFound : public FtpSocketDataProvider { public: - FtpSocketDataProviderFileNotFound() { - } + FtpSocketDataProviderFileNotFound() {} + ~FtpSocketDataProviderFileNotFound() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -494,8 +475,8 @@ class FtpSocketDataProviderFileDownloadWithPasvFallback : public FtpSocketDataProviderFileDownload { public: - FtpSocketDataProviderFileDownloadWithPasvFallback() { - } + FtpSocketDataProviderFileDownloadWithPasvFallback() {} + ~FtpSocketDataProviderFileDownloadWithPasvFallback() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -519,8 +500,8 @@ class FtpSocketDataProviderFileDownloadZeroSize : public FtpSocketDataProviderFileDownload { public: - FtpSocketDataProviderFileDownloadZeroSize() { - } + FtpSocketDataProviderFileDownloadZeroSize() {} + ~FtpSocketDataProviderFileDownloadZeroSize() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -545,8 +526,8 @@ class FtpSocketDataProviderFileDownloadCWD451 : public FtpSocketDataProviderFileDownload { public: - FtpSocketDataProviderFileDownloadCWD451() { - } + FtpSocketDataProviderFileDownloadCWD451() {} + ~FtpSocketDataProviderFileDownloadCWD451() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -567,8 +548,8 @@ class FtpSocketDataProviderVMSFileDownload : public FtpSocketDataProvider { public: - FtpSocketDataProviderVMSFileDownload() { - } + FtpSocketDataProviderVMSFileDownload() {} + ~FtpSocketDataProviderVMSFileDownload() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -603,8 +584,8 @@ class FtpSocketDataProviderEscaping : public FtpSocketDataProviderFileDownload { public: - FtpSocketDataProviderEscaping() { - } + FtpSocketDataProviderEscaping() {} + ~FtpSocketDataProviderEscaping() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -629,60 +610,11 @@ DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEscaping); }; -class FtpSocketDataProviderFileDownloadTransferStarting - : public FtpSocketDataProviderFileDownload { - public: - FtpSocketDataProviderFileDownloadTransferStarting() { - } - - MockWriteResult OnWrite(const std::string& data) override { - if (InjectFault()) - return MockWriteResult(ASYNC, data.length()); - switch (state()) { - case PRE_RETR: - return Verify("RETR /file\r\n", data, PRE_QUIT, - "125-Data connection already open.\r\n" - "125 Transfer starting.\r\n" - "226 Transfer complete.\r\n"); - default: - return FtpSocketDataProviderFileDownload::OnWrite(data); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadTransferStarting); -}; - -class FtpSocketDataProviderDirectoryListingTransferStarting - : public FtpSocketDataProviderDirectoryListing { - public: - FtpSocketDataProviderDirectoryListingTransferStarting() { - } - - MockWriteResult OnWrite(const std::string& data) override { - if (InjectFault()) - return MockWriteResult(ASYNC, data.length()); - switch (state()) { - case PRE_LIST: - return Verify("LIST -l\r\n", data, PRE_QUIT, - "125-Data connection already open.\r\n" - "125 Transfer starting.\r\n" - "226 Transfer complete.\r\n"); - default: - return FtpSocketDataProviderDirectoryListing::OnWrite(data); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN( - FtpSocketDataProviderDirectoryListingTransferStarting); -}; - class FtpSocketDataProviderFileDownloadInvalidResponse : public FtpSocketDataProviderFileDownload { public: - FtpSocketDataProviderFileDownloadInvalidResponse() { - } + FtpSocketDataProviderFileDownloadInvalidResponse() {} + ~FtpSocketDataProviderFileDownloadInvalidResponse() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -718,6 +650,8 @@ epsv_response_length_(epsv_response_length), expected_state_(expected_state) {} + ~FtpSocketDataProviderEvilEpsv() override {} + MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) return MockWriteResult(ASYNC, data.length()); @@ -731,7 +665,7 @@ } private: - const char* epsv_response_; + const char* const epsv_response_; const size_t epsv_response_length_; const State expected_state_; @@ -745,6 +679,7 @@ : pasv_response_(pasv_response), expected_state_(expected_state) { } + ~FtpSocketDataProviderEvilPasv() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -758,7 +693,7 @@ } private: - const char* pasv_response_; + const char* const pasv_response_; const State expected_state_; DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilPasv); @@ -770,6 +705,7 @@ : size_response_(size_response), expected_state_(expected_state) { } + ~FtpSocketDataProviderEvilSize() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -783,7 +719,7 @@ } private: - const char* size_response_; + const char* const size_response_; const State expected_state_; DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilSize); @@ -797,6 +733,7 @@ : expected_user_(expected_user), expected_password_(expected_password) { } + ~FtpSocketDataProviderEvilLogin() override {} MockWriteResult OnWrite(const std::string& data) override { if (InjectFault()) @@ -814,51 +751,12 @@ } private: - const char* expected_user_; - const char* expected_password_; + const char* const expected_user_; + const char* const expected_password_; DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilLogin); }; -class FtpSocketDataProviderCloseConnection : public FtpSocketDataProvider { - public: - FtpSocketDataProviderCloseConnection() { - } - - MockWriteResult OnWrite(const std::string& data) override { - if (InjectFault()) - return MockWriteResult(ASYNC, data.length()); - switch (state()) { - case PRE_USER: - return Verify("USER anonymous\r\n", data, - PRE_QUIT, ""); - default: - return FtpSocketDataProvider::OnWrite(data); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderCloseConnection); -}; - -class BorkedFtpSocketDataProvider : public FtpSocketDataProvider { - public: - BorkedFtpSocketDataProvider() {} - ~BorkedFtpSocketDataProvider() override {} - - MockWriteResult OnWrite(const std::string& data) override { - switch (state()) { - case PRE_USER: - return Verify("USER anonymous\r\n", data, PRE_PASSWD, "957 Spam\r\n"); - default: - return FtpSocketDataProvider::OnWrite(data); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(BorkedFtpSocketDataProvider); -}; - class FtpNetworkTransactionTest : public PlatformTest, public ::testing::WithParamInterface<int> { @@ -877,14 +775,15 @@ } host_resolver_->set_rules(rules.get()); } + ~FtpNetworkTransactionTest() override {} // Sets up an FtpNetworkTransaction and MocketClientSocketFactory, replacing // the default one. Only needs to be called if a test runs multiple // transactions. void SetUpTransaction() { - mock_socket_factory_.reset(new MockClientSocketFactory()); - transaction_.reset(new FtpNetworkTransaction(host_resolver_.get(), - mock_socket_factory_.get())); + mock_socket_factory_ = base::MakeUnique<MockClientSocketFactory>(); + transaction_ = base::MakeUnique<FtpNetworkTransaction>( + host_resolver_.get(), mock_socket_factory_.get()); } protected: @@ -916,9 +815,9 @@ MockRead(mock_data.c_str()), }; - std::unique_ptr<StaticSocketDataProvider> data_socket( - new StaticSocketDataProvider(data_reads, arraysize(data_reads), NULL, - 0)); + std::unique_ptr<StaticSocketDataProvider> data_socket = + base::MakeUnique<StaticSocketDataProvider>( + data_reads, arraysize(data_reads), nullptr, 0); mock_socket_factory_->AddSocketDataProvider(data_socket.get()); FtpRequestInfo request_info = GetRequestInfo(request); EXPECT_EQ(LOAD_STATE_IDLE, transaction_->GetLoadState()); @@ -968,7 +867,7 @@ TEST_P(FtpNetworkTransactionTest, FailedLookup) { FtpRequestInfo request_info = GetRequestInfo("ftp://badhost"); scoped_refptr<RuleBasedHostResolverProc> rules( - new RuleBasedHostResolverProc(NULL)); + new RuleBasedHostResolverProc(nullptr)); rules->AddSimulatedFailure("badhost"); host_resolver_->set_rules(rules.get()); @@ -1056,7 +955,9 @@ // Regression test for http://crbug.com/60555. TEST_P(FtpNetworkTransactionTest, DirectoryTransactionZeroSize) { - FtpSocketDataProviderDirectoryListingZeroSize ctrl_socket; + FtpSocketDataProviderDirectoryListing ctrl_socket; + ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_SIZE, + FtpSocketDataProvider::PRE_CWD, "213 0\r\n"); ExecuteTransaction(&ctrl_socket, "ftp://host", OK); } @@ -1071,7 +972,12 @@ } TEST_P(FtpNetworkTransactionTest, DirectoryTransactionTransferStarting) { - FtpSocketDataProviderDirectoryListingTransferStarting ctrl_socket; + FtpSocketDataProviderDirectoryListing ctrl_socket; + ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_LIST, + FtpSocketDataProvider::PRE_QUIT, + "125-Data connection already open.\r\n" + "125 Transfer starting.\r\n" + "226 Transfer complete.\r\n"); ExecuteTransaction(&ctrl_socket, "ftp://host", OK); } @@ -1145,7 +1051,12 @@ } TEST_P(FtpNetworkTransactionTest, DownloadTransactionTransferStarting) { - FtpSocketDataProviderFileDownloadTransferStarting ctrl_socket; + FtpSocketDataProviderFileDownload ctrl_socket; + ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_RETR, + FtpSocketDataProvider::PRE_QUIT, + "125-Data connection already open.\r\n" + "125 Transfer starting.\r\n" + "226 Transfer complete.\r\n"); ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); } @@ -1225,7 +1136,7 @@ }; StaticSocketDataProvider data_socket1; StaticSocketDataProvider data_socket2(data_reads, arraysize(data_reads), - NULL, 0); + nullptr, 0); mock_socket_factory_->AddSocketDataProvider(&ctrl_socket); mock_socket_factory_->AddSocketDataProvider(&data_socket1); mock_socket_factory_->AddSocketDataProvider(&data_socket2); @@ -1514,7 +1425,9 @@ // Regression test for http://crbug.com/25023. TEST_P(FtpNetworkTransactionTest, CloseConnection) { - FtpSocketDataProviderCloseConnection ctrl_socket; + FtpSocketDataProvider ctrl_socket; + ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_USER, + FtpSocketDataProvider::PRE_QUIT, ""); ExecuteTransaction(&ctrl_socket, "ftp://host", ERR_EMPTY_RESPONSE); } @@ -1808,7 +1721,7 @@ "257 \"foo\nbar\" is your current location\r\n", ERR_INVALID_RESPONSE); } -INSTANTIATE_TEST_CASE_P(FTP, +INSTANTIATE_TEST_CASE_P(Ftp, FtpNetworkTransactionTest, ::testing::Values(AF_INET, AF_INET6));
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc index b4a6bd46..6b052ad 100644 --- a/net/http/http_stream_factory_impl_job_controller.cc +++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -636,16 +636,16 @@ void HttpStreamFactoryImpl::JobController:: RemoveRequestFromSpdySessionRequestMap() { - const SpdySessionKey* spdy_session_key = request_->spdy_session_key(); - if (spdy_session_key) { + if (request_->HasSpdySessionKey()) { + const SpdySessionKey& spdy_session_key = request_->GetSpdySessionKey(); SpdySessionRequestMap& spdy_session_request_map = factory_->spdy_session_request_map_; - DCHECK(base::ContainsKey(spdy_session_request_map, *spdy_session_key)); - RequestSet& request_set = spdy_session_request_map[*spdy_session_key]; + DCHECK(base::ContainsKey(spdy_session_request_map, spdy_session_key)); + RequestSet& request_set = spdy_session_request_map[spdy_session_key]; DCHECK(base::ContainsKey(request_set, request_)); request_set.erase(request_); if (request_set.empty()) - spdy_session_request_map.erase(*spdy_session_key); + spdy_session_request_map.erase(spdy_session_key); request_->ResetSpdySessionKey(); } }
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc index 76abed6..8cefe1d4 100644 --- a/net/http/http_stream_factory_impl_request.cc +++ b/net/http/http_stream_factory_impl_request.cc
@@ -44,11 +44,6 @@ helper_->OnRequestComplete(); } -void HttpStreamFactoryImpl::Request::SetSpdySessionKey( - const SpdySessionKey& spdy_session_key) { - spdy_session_key_.reset(new SpdySessionKey(spdy_session_key)); -} - void HttpStreamFactoryImpl::Request::Complete(bool was_alpn_negotiated, NextProto negotiated_protocol, bool using_spdy) { @@ -154,16 +149,6 @@ return connection_attempts_; } -void HttpStreamFactoryImpl::Request::ResetSpdySessionKey() { - if (spdy_session_key_.get()) { - spdy_session_key_.reset(); - } -} - -bool HttpStreamFactoryImpl::Request::HasSpdySessionKey() const { - return spdy_session_key_.get() != NULL; -} - void HttpStreamFactoryImpl::Request::AddConnectionAttempts( const ConnectionAttempts& attempts) { for (const auto& attempt : attempts)
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h index 703dedd..266dd44 100644 --- a/net/http/http_stream_factory_impl_request.h +++ b/net/http/http_stream_factory_impl_request.h
@@ -9,6 +9,7 @@ #include <set> #include "base/macros.h" +#include "base/optional.h" #include "net/base/net_export.h" #include "net/http/http_stream_factory_impl.h" #include "net/log/net_log_with_source.h" @@ -63,16 +64,23 @@ // for the Request. Note that this does not mean that SPDY is necessarily // supported for this SpdySessionKey, since we may need to wait for NPN to // complete before knowing if SPDY is available. - void SetSpdySessionKey(const SpdySessionKey& spdy_session_key); - bool HasSpdySessionKey() const; + void SetSpdySessionKey(const SpdySessionKey& spdy_session_key) { + spdy_session_key_ = spdy_session_key; + } + bool HasSpdySessionKey() const { return spdy_session_key_.has_value(); } + const SpdySessionKey& GetSpdySessionKey() const { + DCHECK(HasSpdySessionKey()); + return spdy_session_key_.value(); + } + void ResetSpdySessionKey() { spdy_session_key_.reset(); } + + HttpStreamRequest::StreamType stream_type() const { return stream_type_; } // Marks completion of the request. Must be called before OnStreamReady(). void Complete(bool was_alpn_negotiated, NextProto negotiated_protocol, bool using_spdy); - void ResetSpdySessionKey(); - // Called by |helper_| to record connection attempts made by the socket // layer in an attached Job for this stream request. void AddConnectionAttempts(const ConnectionAttempts& attempts); @@ -84,7 +92,6 @@ // HttpStreamRequest::Delegate methods which we implement. Note we don't // actually subclass HttpStreamRequest::Delegate. - void OnStreamReady(const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, HttpStream* stream); @@ -112,7 +119,6 @@ HttpStream* stream); // HttpStreamRequest methods. - int RestartTunnelWithProxyAuth() override; void SetPriority(RequestPriority priority) override; LoadState GetLoadState() const override; @@ -120,10 +126,6 @@ NextProto negotiated_protocol() const override; bool using_spdy() const override; const ConnectionAttempts& connection_attempts() const override; - HttpStreamRequest::StreamType stream_type() const { return stream_type_; } - const SpdySessionKey* spdy_session_key() const { - return spdy_session_key_.get(); - } private: const GURL url_; @@ -136,7 +138,7 @@ HttpStreamRequest::Delegate* const delegate_; const NetLogWithSource net_log_; - std::unique_ptr<const SpdySessionKey> spdy_session_key_; + base::Optional<SpdySessionKey> spdy_session_key_; bool completed_; bool was_alpn_negotiated_;
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc index 666a9d7..cd7e59c3 100644 --- a/net/quic/core/congestion_control/bbr_sender.cc +++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -46,6 +46,12 @@ // will exit the STARTUP mode. const float kStartupGrowthTarget = 1.25; const QuicRoundTripCount kRoundTripsWithoutGrowthBeforeExitingStartup = 3; + +// Maintain ack history for this fraction of the smoothed RTT. +const float kRecentlyAckedRttFraction = 0.5f; +// Minimum period over which ack history will be maintained. +const QuicTime::Delta kMinAckHistory = QuicTime::Delta::FromMilliseconds(5); + } // namespace BbrSender::DebugState::DebugState(const BbrSender& sender) @@ -93,10 +99,14 @@ pacing_gain_(1), congestion_window_gain_(1), congestion_window_gain_constant_( - static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_cwnd_gain))), + static_cast<float>(FLAGS_quic_bbr_cwnd_gain)), rtt_variance_weight_( - static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_rtt_variation_weight))), + static_cast<float>(FLAGS_quic_bbr_rtt_variation_weight)), num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), + congestion_window_gain_for_slow_delivery_( + static_cast<float>(FLAGS_quic_bbr_slow_delivery_cwnd_gain)), + threshold_multiplier_for_slow_delivery_(static_cast<float>( + FLAGS_quic_bbr_slow_delivery_threshold_multiplier)), cycle_current_offset_(0), last_cycle_start_(QuicTime::Zero()), is_at_full_bandwidth_(false), @@ -108,7 +118,8 @@ last_sample_is_app_limited_(false), recovery_state_(NOT_IN_RECOVERY), end_recovery_at_(0), - recovery_window_(max_congestion_window_) { + recovery_window_(max_congestion_window_), + bytes_recently_acked_(0) { EnterStartupMode(); } @@ -134,11 +145,45 @@ return is_retransmittable == HAS_RETRANSMITTABLE_DATA; } -QuicTime::Delta BbrSender::TimeUntilSend(QuicTime /* now */, - QuicByteCount bytes_in_flight) const { +bool BbrSender::SlowDeliveryAllowsSending(QuicTime now, + QuicByteCount bytes_in_flight) { + if (mode_ != BbrSender::PROBE_BW) { + return false; + } + UpdateRecentlyAcked(now, 0u); + // Set a (large) limit to how much we send into a blackhole. + if (bytes_in_flight >= + congestion_window_gain_for_slow_delivery_ * GetCongestionWindow()) { + return false; + } + // If no acks were recorded in the recent past, continue sending. + if (recently_acked_.empty()) { + return true; + } + // Compute the time period over which acks should have been recorded. + QuicTime::Delta ack_period = + std::max(now - recently_acked_.front().ack_time, + std::max(kMinAckHistory, kRecentlyAckedRttFraction * + rtt_stats_->smoothed_rtt())); + // If delivery rate is less than BW by a factor of threshold_multiplier_, + // ack rate has suddenly decreased substantially. Continue sending. + if (BandwidthEstimate() * ack_period > + threshold_multiplier_for_slow_delivery_ * bytes_recently_acked_) { + return true; + } + return false; +} + +QuicTime::Delta BbrSender::TimeUntilSend(QuicTime now, + QuicByteCount bytes_in_flight) { if (bytes_in_flight < GetCongestionWindow()) { return QuicTime::Delta::Zero(); } + if (FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery && + SlowDeliveryAllowsSending(now, bytes_in_flight)) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_slow_recent_delivery, 2, 2); + return QuicTime::Delta::Zero(); + } return QuicTime::Delta::Infinite(); } @@ -247,6 +292,14 @@ min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), is_round_start); + + if (FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_slow_recent_delivery, 1, + 2); + UpdateRecentlyAcked( + event_time, sampler_.total_bytes_acked() - total_bytes_acked_before); + } + if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 1, 2); @@ -515,11 +568,51 @@ // Exit recovery if appropriate. if (!has_losses && last_acked_packet > end_recovery_at_) { recovery_state_ = NOT_IN_RECOVERY; + return; + } + + if (!FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation) { + return; + } + + // Use "single round in conservation" approach outside of PROBE_BW. + if (mode_ != PROBE_BW) { + return; + } + + // Switch between conservation and growth depending on position in the + // gain cycle. + if (cycle_current_offset_ == 0 || + cycle_current_offset_ == kGainCycleLength - 1) { + recovery_state_ = GROWTH; + } else { + recovery_state_ = CONSERVATION; } break; } } +void BbrSender::UpdateRecentlyAcked(QuicTime new_ack_time, + QuicByteCount newly_acked_bytes) { + // Discard information stored for acks received too far in the past. + QuicTime::Delta recent_period = std::max( + kMinAckHistory, kRecentlyAckedRttFraction * rtt_stats_->smoothed_rtt()); + while (!recently_acked_.empty() && + (recently_acked_.front().ack_time + recent_period < new_ack_time)) { + DCHECK_GE(bytes_recently_acked_, recently_acked_.front().acked_bytes); + bytes_recently_acked_ -= recently_acked_.front().acked_bytes; + recently_acked_.pop_front(); + } + // Nothing to add to recently_acked_ if no new ack. + if (newly_acked_bytes == 0) + return; + // Add information for new ack + DataDelivered new_ack = {new_ack_time, newly_acked_bytes}; + recently_acked_.push_back(new_ack); + bytes_recently_acked_ += newly_acked_bytes; +} + +// TODO(ianswett): Move this logic into BandwidthSampler. void BbrSender::UpdateAckAggregationBytes(QuicTime ack_time, QuicByteCount newly_acked_bytes) { // Compute how many bytes are expected to be delivered, assuming max bandwidth
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h index 9a6cd7e3..cc76f76 100644 --- a/net/quic/core/congestion_control/bbr_sender.h +++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -119,7 +119,7 @@ void OnRetransmissionTimeout(bool packets_retransmitted) override {} void OnConnectionMigration() override {} QuicTime::Delta TimeUntilSend(QuicTime now, - QuicByteCount bytes_in_flight) const override; + QuicByteCount bytes_in_flight) override; QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; QuicBandwidth BandwidthEstimate() const override; QuicByteCount GetCongestionWindow() const override; @@ -196,6 +196,16 @@ bool has_losses, bool is_round_start); + // Returns true if recent ack rate has decreased substantially and if sender + // is allowed to continue sending when congestion window limited. + bool SlowDeliveryAllowsSending(QuicTime now, QuicByteCount bytes_in_flight); + + // Updates history of recently received acks. Acks are considered recent + // if received within kRecentlyAckedRttFraction x smoothed RTT in the past. + // Adds new ack to recently_acked_ if |newly_acked_bytes| is non-zero. + void UpdateRecentlyAcked(QuicTime new_ack_time, + QuicByteCount newly_acked_bytes); + // Updates the ack aggregation max filter in bytes. void UpdateAckAggregationBytes(QuicTime ack_time, QuicByteCount newly_acked_bytes); @@ -270,6 +280,13 @@ // The number of RTTs to stay in STARTUP mode. Defaults to 3. QuicRoundTripCount num_startup_rtts_; + // Gain to use when delivery rate is slow. + // TODO(jri): Make this a constant if we decide to use this code for BBR. + const float congestion_window_gain_for_slow_delivery_; + // Threshold multiplier below which delivery is considered slow. + // TODO(jri): Make this a constant if we decide to use this code for BBR. + const float threshold_multiplier_for_slow_delivery_; + // Number of round-trips in PROBE_BW mode, used for determining the current // pacing gain cycle. int cycle_current_offset_; @@ -305,6 +322,17 @@ // A window used to limit the number of bytes in flight during loss recovery. QuicByteCount recovery_window_; + // Records information about a received ack + struct DataDelivered { + QuicTime ack_time; + QuicByteCount acked_bytes; + }; + + // Data structure to record recently received acks. Used for determining + // recently seen ack rate over a short period in the past. + std::deque<DataDelivered> recently_acked_; + QuicByteCount bytes_recently_acked_; + DISALLOW_COPY_AND_ASSIGN(BbrSender); };
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc index f89c8ad..872b863 100644 --- a/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -92,6 +92,7 @@ {&receiver_, &competing_receiver_}) { // 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; rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats(); sender_ = SetupBbrSender(&bbr_sender_); @@ -337,7 +338,8 @@ sender_->ExportDebugState().max_bandwidth); // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures // bandwidth higher than the link rate. - EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + // TODO(vasilvv): figure out why the line below is occasionally flaky. + // 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.5, rtt_stats_->smoothed_rtt()); @@ -348,7 +350,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes = true; // Decrease the CWND gain so extra CWND is required with stretch acks. - SetQuicFlag(&FLAGS_quic_bbr_cwnd_gain, 1.0); + FLAGS_quic_bbr_cwnd_gain = 1.0; sender_ = new BbrSender( rtt_stats_, QuicSentPacketManagerPeer::GetUnackedPacketMap( @@ -385,7 +387,7 @@ FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = true; FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate = true; // Decrease the CWND gain so extra CWND is required with stretch acks. - SetQuicFlag(&FLAGS_quic_bbr_cwnd_gain, 1.0); + FLAGS_quic_bbr_cwnd_gain = 1.0; sender_ = new BbrSender( rtt_stats_, QuicSentPacketManagerPeer::GetUnackedPacketMap( @@ -417,6 +419,38 @@ ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f); } +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, + SimpleTransfer2RTTAggregationBytesWithIncreasedInflightLimit) { + FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes = false; + FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate = false; + FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery = true; + FLAGS_quic_bbr_slow_delivery_threshold_multiplier = 0.5; + FLAGS_quic_bbr_slow_delivery_cwnd_gain = 4.0; + CreateDefaultSetup(); + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * kTestRtt); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 50% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.5f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + 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); +} + // Test the number of losses incurred by the startup phase in a situation when // the buffer is less than BDP. TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartup) { @@ -432,6 +466,12 @@ // Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY // -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY). TEST_F(BbrSenderTest, RecoveryStates) { + // Set seed to the position where the gain cycling causes the sender go + // into conservation upon entering PROBE_BW. + // + // TODO(vasilvv): there should be a better way to test this. + random_.set_seed(UINT64_C(14719894707049085006)); + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); bool simulator_result; CreateSmallBufferSetup(); @@ -464,9 +504,16 @@ return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH; }, timeout); + + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + if (FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation) { + ASSERT_EQ(BbrSender::CONSERVATION, + sender_->ExportDebugState().recovery_state); + } else { + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + } ASSERT_TRUE(simulator_result); - ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, - sender_->ExportDebugState().recovery_state); } // Verify the behavior of the algorithm in the case when the connection sends
diff --git a/net/quic/core/congestion_control/send_algorithm_interface.h b/net/quic/core/congestion_control/send_algorithm_interface.h index dacccba..5abb3e9 100644 --- a/net/quic/core/congestion_control/send_algorithm_interface.h +++ b/net/quic/core/congestion_control/send_algorithm_interface.h
@@ -82,9 +82,8 @@ virtual void OnConnectionMigration() = 0; // Calculate the time until we can send the next packet. - virtual QuicTime::Delta TimeUntilSend( - QuicTime now, - QuicByteCount bytes_in_flight) const = 0; + virtual QuicTime::Delta TimeUntilSend(QuicTime now, + QuicByteCount bytes_in_flight) = 0; // The pacing rate of the send algorithm. May be zero if the rate is unknown. virtual QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const = 0;
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc index 151cc3e..d56fbf8 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc +++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
@@ -188,7 +188,7 @@ QuicTime::Delta TcpCubicSenderBase::TimeUntilSend( QuicTime /* now */, - QuicByteCount bytes_in_flight) const { + QuicByteCount bytes_in_flight) { if (!no_prr_ && InRecovery()) { // PRR is used when in recovery. return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight,
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.h b/net/quic/core/congestion_control/tcp_cubic_sender_base.h index a4ac1e57..2488bf2 100644 --- a/net/quic/core/congestion_control/tcp_cubic_sender_base.h +++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.h
@@ -62,7 +62,7 @@ void OnRetransmissionTimeout(bool packets_retransmitted) override; void OnConnectionMigration() override; QuicTime::Delta TimeUntilSend(QuicTime now, - QuicByteCount bytes_in_flight) const override; + QuicByteCount bytes_in_flight) override; QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; QuicBandwidth BandwidthEstimate() const override; bool InSlowStart() const override;
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index e59f187..d1bc575e 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -204,3 +204,16 @@ // If true, enable random padding of size [1, 256] when response body is // compressed for QUIC version >= 38. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_random_padding, false) + +// Use conservation in PROBE_BW ouside of super-unity gain and immediately +// preceeding cycle. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation, false) + +// Increase BBR's inflight limit if recent ack rate is low. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery, false) + +// Congestion window gain for QUIC BBR during slow delivery. +QUIC_FLAG(double, FLAGS_quic_bbr_slow_delivery_cwnd_gain, 4.0f) + +// Threshold multiplier below which delivery is considered slow. +QUIC_FLAG(double, FLAGS_quic_bbr_slow_delivery_threshold_multiplier, 0.5f)
diff --git a/net/quic/core/quic_version_manager.cc b/net/quic/core/quic_version_manager.cc index fb8bdf0..7652813 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_(GetQuicFlag(FLAGS_quic_enable_version_39)), + : enable_version_39_(FLAGS_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_ != GetQuicFlag(FLAGS_quic_enable_version_39) || + if (enable_version_39_ != FLAGS_quic_enable_version_39 || enable_version_38_ != FLAGS_quic_reloadable_flag_quic_enable_version_38) { - enable_version_39_ = GetQuicFlag(FLAGS_quic_enable_version_39); + enable_version_39_ = FLAGS_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_test.cc b/net/quic/core/quic_version_manager_test.cc index 05691b55..b2ddbf5 100644 --- a/net/quic/core/quic_version_manager_test.cc +++ b/net/quic/core/quic_version_manager_test.cc
@@ -30,7 +30,7 @@ EXPECT_EQ(QUIC_VERSION_36, manager.GetSupportedVersions()[2]); EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[3]); - SetQuicFlag(&FLAGS_quic_enable_version_39, true); + FLAGS_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 b94997d..4a9583b2 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 (GetQuicFlag(FLAGS_quic_enable_version_39) && + if (FLAGS_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_test.cc b/net/quic/core/quic_versions_test.cc index 0b392a9e..42493cf 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; - SetQuicFlag(&FLAGS_quic_enable_version_39, false); + FLAGS_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; - SetQuicFlag(&FLAGS_quic_enable_version_39, true); + FLAGS_quic_enable_version_39 = true; QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions); ASSERT_EQ(all_versions, filtered_versions);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 1eb3868e..f30363d1 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -758,9 +758,8 @@ MOCK_METHOD1(OnRetransmissionTimeout, void(bool)); MOCK_METHOD0(OnConnectionMigration, void()); MOCK_METHOD0(RevertRetransmissionTimeout, void()); - MOCK_CONST_METHOD2(TimeUntilSend, - QuicTime::Delta(QuicTime now, - QuicByteCount bytes_in_flight)); + MOCK_METHOD2(TimeUntilSend, + QuicTime::Delta(QuicTime now, QuicByteCount bytes_in_flight)); MOCK_CONST_METHOD1(PacingRate, QuicBandwidth(QuicByteCount)); MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void)); MOCK_CONST_METHOD0(HasReliableBandwidthEstimate, bool());
diff --git a/net/tools/quic/platform/impl/quic_socket_utils.cc b/net/tools/quic/platform/impl/quic_socket_utils.cc index d602ac35..621767c 100644 --- a/net/tools/quic/platform/impl/quic_socket_utils.cc +++ b/net/tools/quic/platform/impl/quic_socket_utils.cc
@@ -10,6 +10,7 @@ #include <string.h> #include <sys/socket.h> #include <sys/uio.h> +#include <unistd.h> #include <string> #include "net/quic/core/quic_packets.h"
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 3f3f235..2b582dde 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -535,7 +535,7 @@ static_assert(arraysize(kSupportedQuicVersions) == 5u, "Supported versions out of sync"); FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - SetQuicFlag(&FLAGS_quic_enable_version_39, true); + FLAGS_quic_enable_version_39 = true; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); QuicConnectionId connection_id = 1; @@ -575,7 +575,7 @@ PACKET_6BYTE_PACKET_NUMBER, 1); // Turn off version 39. - SetQuicFlag(&FLAGS_quic_enable_version_39, false); + FLAGS_quic_enable_version_39 = false; ++connection_id; EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address)) .Times(0); @@ -584,7 +584,7 @@ PACKET_6BYTE_PACKET_NUMBER, 1); // Turn on version 39. - SetQuicFlag(&FLAGS_quic_enable_version_39, true); + FLAGS_quic_enable_version_39 = true; ++connection_id; EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address)) .WillOnce(testing::Return(CreateSession(
diff --git a/services/ui/gpu/gpu_main.cc b/services/ui/gpu/gpu_main.cc index ba01980..580e5b4fc 100644 --- a/services/ui/gpu/gpu_main.cc +++ b/services/ui/gpu/gpu_main.cc
@@ -166,6 +166,7 @@ cc::mojom::FrameSinkManagerRequest request, cc::mojom::FrameSinkManagerClientPtrInfo client_info) { DCHECK(!gpu_command_service_); + DCHECK(gpu_service_); gpu_command_service_ = new gpu::GpuInProcessThreadService( gpu_thread_task_runner_, gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(), gpu_service_->share_group());
diff --git a/styleguide/styleguide.md b/styleguide/styleguide.md index 4af45ddd..1a24bb5e 100644 --- a/styleguide/styleguide.md +++ b/styleguide/styleguide.md
@@ -43,6 +43,6 @@ ## Web languages (JavaScript, HTML, CSS) -When working on Web-based UI features, consult the [Web Development Style Guide](https://sites.google.com/a/chromium.org/dev/developers/web-development-style-guide) for the Chromium conventions used in JS/CSS/HTML files. +When working on Web-based UI features, consult the [Web Development Style Guide](web/web.md) for the Chromium conventions used in JS/CSS/HTML files. Internal uses of web languages, notably "layout" tests, should preferably follow these style guides, but it is not enforced.
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index 584f799..8e9191c 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1412,6 +1412,7 @@ crbug.com/589265 virtual/threaded/animations/animated-filter-svg-element.html [ Failure Crash ] # Some work remains to fully support composited animation and scrolling. +Bug(none) virtual/threaded/animations/css-animation-affects-use-elements.html [ Failure ] Bug(none) virtual/threaded/animations/composited-animation-style-update.html [ Failure ] crbug.com/702350 transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ] crbug.com/702350 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ] @@ -1420,7 +1421,7 @@ crbug.com/702353 virtual/threaded/transitions/extra-transition.html [ Timeout ] crbug.com/702365 virtual/threaded/animations/composited-filter-webkit-filter.html [ Failure ] crbug.com/702370 virtual/threaded/animations/compositor-independent-transform-cancel.html [ Failure ] -crbug.com/702379 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure ] +crbug.com/702379 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure Crash ] crbug.com/692310 virtual/threaded/animations/3d/replace-filling-transform.html [ Crash ] crbug.com/692310 virtual/threaded/animations/change-transform-style-during-animation.html [ Crash ] crbug.com/692310 virtual/threaded/animations/fill-mode-transform.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt index 44200e0..8a6f9d9 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt
@@ -20,6 +20,8 @@ FAIL MediaCapabilities interface: operation decodingInfo(MediaDecodingConfiguration) assert_throws: calling operation with this = null didn't throw TypeError function "function () { fn.apply(obj, args); }" did not throw -FAIL MediaCapabilities interface: operation encodingInfo(MediaEncodingConfiguration) assert_own_property: interface prototype object missing non-static operation expected property "encodingInfo" missing +FAIL MediaCapabilities interface: operation encodingInfo(MediaEncodingConfiguration) assert_throws: calling operation with this = null didn't throw TypeError function "function () { + fn.apply(obj, args); + }" did not throw Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt index 389da5ae..f4fb539 100644 --- a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE WARNING: line 1: The rtcpMuxPolicy option is being considered for removal and may be removed no earlier than M60, around August 2017. If you depend on it, please see https://www.chromestatus.com/features/5654810086866944 for more details. +CONSOLE WARNING: line 1: The rtcpMuxPolicy option is being considered for removal and may be removed no earlier than M62, around October 2017. If you depend on it, please see https://www.chromestatus.com/features/5654810086866944 for more details. CONSOLE WARNING: line 1: Unknown constraint named invalid rejected CONSOLE WARNING: line 1: Unknown constraint named valid_but_unsupported_1 rejected CONSOLE WARNING: line 1: Unknown constraint named valid_but_unsupported_1 rejected
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js new file mode 100644 index 0000000..bc2e35d --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
@@ -0,0 +1,376 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-wasm + +function bytes() { + var buffer = new ArrayBuffer(arguments.length); + var view = new Uint8Array(buffer); + for (var i = 0; i < arguments.length; i++) { + var val = arguments[i]; + if ((typeof val) == "string") val = val.charCodeAt(0); + view[i] = val | 0; + } + return buffer; +} + +// Header declaration constants +var kWasmH0 = 0; +var kWasmH1 = 0x61; +var kWasmH2 = 0x73; +var kWasmH3 = 0x6d; + +var kWasmV0 = 0x1; +var kWasmV1 = 0; +var kWasmV2 = 0; +var kWasmV3 = 0; + +var kHeaderSize = 8; +var kPageSize = 65536; + +function bytesWithHeader() { + var buffer = new ArrayBuffer(kHeaderSize + arguments.length); + var view = new Uint8Array(buffer); + view[0] = kWasmH0; + view[1] = kWasmH1; + view[2] = kWasmH2; + view[3] = kWasmH3; + view[4] = kWasmV0; + view[5] = kWasmV1; + view[6] = kWasmV2; + view[7] = kWasmV3; + for (var i = 0; i < arguments.length; i++) { + var val = arguments[i]; + if ((typeof val) == "string") val = val.charCodeAt(0); + view[kHeaderSize + i] = val | 0; + } + return buffer; +} + +let kDeclNoLocals = 0; + +// Section declaration constants +let kUnknownSectionCode = 0; +let kTypeSectionCode = 1; // Function signature declarations +let kImportSectionCode = 2; // Import declarations +let kFunctionSectionCode = 3; // Function declarations +let kTableSectionCode = 4; // Indirect function table and other tables +let kMemorySectionCode = 5; // Memory attributes +let kGlobalSectionCode = 6; // Global declarations +let kExportSectionCode = 7; // Exports +let kStartSectionCode = 8; // Start function declaration +let kElementSectionCode = 9; // Elements section +let kCodeSectionCode = 10; // Function code +let kDataSectionCode = 11; // Data segments +let kNameSectionCode = 12; // Name section (encoded as string) + +let kWasmFunctionTypeForm = 0x60; +let kWasmAnyFunctionTypeForm = 0x70; + +let kResizableMaximumFlag = 1; + +// Function declaration flags +let kDeclFunctionName = 0x01; +let kDeclFunctionImport = 0x02; +let kDeclFunctionLocals = 0x04; +let kDeclFunctionExport = 0x08; + +// Local types +let kWasmStmt = 0x40; +let kWasmI32 = 0x7f; +let kWasmI64 = 0x7e; +let kWasmF32 = 0x7d; +let kWasmF64 = 0x7c; +let kWasmS128 = 0x7b; + +let kExternalFunction = 0; +let kExternalTable = 1; +let kExternalMemory = 2; +let kExternalGlobal = 3; + +let kTableZero = 0; +let kMemoryZero = 0; + +// Useful signatures +let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); +let kSig_l_l = makeSig([kWasmI64], [kWasmI64]); +let kSig_i_l = makeSig([kWasmI64], [kWasmI32]); +let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]); +let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]); +let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]); +let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]); +let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]); +let kSig_v_v = makeSig([], []); +let kSig_i_v = makeSig([], [kWasmI32]); +let kSig_l_v = makeSig([], [kWasmI64]); +let kSig_f_v = makeSig([], [kWasmF64]); +let kSig_d_v = makeSig([], [kWasmF64]); +let kSig_v_i = makeSig([kWasmI32], []); +let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []); +let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []); +let kSig_v_l = makeSig([kWasmI64], []); +let kSig_v_d = makeSig([kWasmF64], []); +let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []); +let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []); +let kSig_s_v = makeSig([], [kWasmS128]); + +function makeSig(params, results) { + return {params: params, results: results}; +} + +function makeSig_v_x(x) { + return makeSig([x], []); +} + +function makeSig_v_xx(x) { + return makeSig([x, x], []); +} + +function makeSig_r_v(r) { + return makeSig([], [r]); +} + +function makeSig_r_x(r, x) { + return makeSig([x], [r]); +} + +function makeSig_r_xx(r, x) { + return makeSig([x, x], [r]); +} + +// Opcodes +let kExprUnreachable = 0x00; +let kExprNop = 0x01; +let kExprBlock = 0x02; +let kExprLoop = 0x03; +let kExprIf = 0x04; +let kExprElse = 0x05; +let kExprTry = 0x06; +let kExprCatch = 0x07; +let kExprThrow = 0x08; +let kExprEnd = 0x0b; +let kExprBr = 0x0c; +let kExprBrIf = 0x0d; +let kExprBrTable = 0x0e; +let kExprReturn = 0x0f; +let kExprCallFunction = 0x10; +let kExprCallIndirect = 0x11; +let kExprDrop = 0x1a; +let kExprSelect = 0x1b; +let kExprGetLocal = 0x20; +let kExprSetLocal = 0x21; +let kExprTeeLocal = 0x22; +let kExprGetGlobal = 0x23; +let kExprSetGlobal = 0x24; +let kExprI32Const = 0x41; +let kExprI64Const = 0x42; +let kExprF32Const = 0x43; +let kExprF64Const = 0x44; +let kExprI32LoadMem = 0x28; +let kExprI64LoadMem = 0x29; +let kExprF32LoadMem = 0x2a; +let kExprF64LoadMem = 0x2b; +let kExprI32LoadMem8S = 0x2c; +let kExprI32LoadMem8U = 0x2d; +let kExprI32LoadMem16S = 0x2e; +let kExprI32LoadMem16U = 0x2f; +let kExprI64LoadMem8S = 0x30; +let kExprI64LoadMem8U = 0x31; +let kExprI64LoadMem16S = 0x32; +let kExprI64LoadMem16U = 0x33; +let kExprI64LoadMem32S = 0x34; +let kExprI64LoadMem32U = 0x35; +let kExprI32StoreMem = 0x36; +let kExprI64StoreMem = 0x37; +let kExprF32StoreMem = 0x38; +let kExprF64StoreMem = 0x39; +let kExprI32StoreMem8 = 0x3a; +let kExprI32StoreMem16 = 0x3b; +let kExprI64StoreMem8 = 0x3c; +let kExprI64StoreMem16 = 0x3d; +let kExprI64StoreMem32 = 0x3e; +let kExprMemorySize = 0x3f; +let kExprGrowMemory = 0x40; +let kExprI32Eqz = 0x45; +let kExprI32Eq = 0x46; +let kExprI32Ne = 0x47; +let kExprI32LtS = 0x48; +let kExprI32LtU = 0x49; +let kExprI32GtS = 0x4a; +let kExprI32GtU = 0x4b; +let kExprI32LeS = 0x4c; +let kExprI32LeU = 0x4d; +let kExprI32GeS = 0x4e; +let kExprI32GeU = 0x4f; +let kExprI64Eqz = 0x50; +let kExprI64Eq = 0x51; +let kExprI64Ne = 0x52; +let kExprI64LtS = 0x53; +let kExprI64LtU = 0x54; +let kExprI64GtS = 0x55; +let kExprI64GtU = 0x56; +let kExprI64LeS = 0x57; +let kExprI64LeU = 0x58; +let kExprI64GeS = 0x59; +let kExprI64GeU = 0x5a; +let kExprF32Eq = 0x5b; +let kExprF32Ne = 0x5c; +let kExprF32Lt = 0x5d; +let kExprF32Gt = 0x5e; +let kExprF32Le = 0x5f; +let kExprF32Ge = 0x60; +let kExprF64Eq = 0x61; +let kExprF64Ne = 0x62; +let kExprF64Lt = 0x63; +let kExprF64Gt = 0x64; +let kExprF64Le = 0x65; +let kExprF64Ge = 0x66; +let kExprI32Clz = 0x67; +let kExprI32Ctz = 0x68; +let kExprI32Popcnt = 0x69; +let kExprI32Add = 0x6a; +let kExprI32Sub = 0x6b; +let kExprI32Mul = 0x6c; +let kExprI32DivS = 0x6d; +let kExprI32DivU = 0x6e; +let kExprI32RemS = 0x6f; +let kExprI32RemU = 0x70; +let kExprI32And = 0x71; +let kExprI32Ior = 0x72; +let kExprI32Xor = 0x73; +let kExprI32Shl = 0x74; +let kExprI32ShrS = 0x75; +let kExprI32ShrU = 0x76; +let kExprI32Rol = 0x77; +let kExprI32Ror = 0x78; +let kExprI64Clz = 0x79; +let kExprI64Ctz = 0x7a; +let kExprI64Popcnt = 0x7b; +let kExprI64Add = 0x7c; +let kExprI64Sub = 0x7d; +let kExprI64Mul = 0x7e; +let kExprI64DivS = 0x7f; +let kExprI64DivU = 0x80; +let kExprI64RemS = 0x81; +let kExprI64RemU = 0x82; +let kExprI64And = 0x83; +let kExprI64Ior = 0x84; +let kExprI64Xor = 0x85; +let kExprI64Shl = 0x86; +let kExprI64ShrS = 0x87; +let kExprI64ShrU = 0x88; +let kExprI64Rol = 0x89; +let kExprI64Ror = 0x8a; +let kExprF32Abs = 0x8b; +let kExprF32Neg = 0x8c; +let kExprF32Ceil = 0x8d; +let kExprF32Floor = 0x8e; +let kExprF32Trunc = 0x8f; +let kExprF32NearestInt = 0x90; +let kExprF32Sqrt = 0x91; +let kExprF32Add = 0x92; +let kExprF32Sub = 0x93; +let kExprF32Mul = 0x94; +let kExprF32Div = 0x95; +let kExprF32Min = 0x96; +let kExprF32Max = 0x97; +let kExprF32CopySign = 0x98; +let kExprF64Abs = 0x99; +let kExprF64Neg = 0x9a; +let kExprF64Ceil = 0x9b; +let kExprF64Floor = 0x9c; +let kExprF64Trunc = 0x9d; +let kExprF64NearestInt = 0x9e; +let kExprF64Sqrt = 0x9f; +let kExprF64Add = 0xa0; +let kExprF64Sub = 0xa1; +let kExprF64Mul = 0xa2; +let kExprF64Div = 0xa3; +let kExprF64Min = 0xa4; +let kExprF64Max = 0xa5; +let kExprF64CopySign = 0xa6; +let kExprI32ConvertI64 = 0xa7; +let kExprI32SConvertF32 = 0xa8; +let kExprI32UConvertF32 = 0xa9; +let kExprI32SConvertF64 = 0xaa; +let kExprI32UConvertF64 = 0xab; +let kExprI64SConvertI32 = 0xac; +let kExprI64UConvertI32 = 0xad; +let kExprI64SConvertF32 = 0xae; +let kExprI64UConvertF32 = 0xaf; +let kExprI64SConvertF64 = 0xb0; +let kExprI64UConvertF64 = 0xb1; +let kExprF32SConvertI32 = 0xb2; +let kExprF32UConvertI32 = 0xb3; +let kExprF32SConvertI64 = 0xb4; +let kExprF32UConvertI64 = 0xb5; +let kExprF32ConvertF64 = 0xb6; +let kExprF64SConvertI32 = 0xb7; +let kExprF64UConvertI32 = 0xb8; +let kExprF64SConvertI64 = 0xb9; +let kExprF64UConvertI64 = 0xba; +let kExprF64ConvertF32 = 0xbb; +let kExprI32ReinterpretF32 = 0xbc; +let kExprI64ReinterpretF64 = 0xbd; +let kExprF32ReinterpretI32 = 0xbe; +let kExprF64ReinterpretI64 = 0xbf; + +let kTrapUnreachable = 0; +let kTrapMemOutOfBounds = 1; +let kTrapDivByZero = 2; +let kTrapDivUnrepresentable = 3; +let kTrapRemByZero = 4; +let kTrapFloatUnrepresentable = 5; +let kTrapFuncInvalid = 6; +let kTrapFuncSigMismatch = 7; +let kTrapInvalidIndex = 8; + +let kTrapMsgs = [ + "unreachable", + "memory access out of bounds", + "divide by zero", + "divide result unrepresentable", + "remainder by zero", + "integer result unrepresentable", + "invalid function", + "function signature mismatch", + "invalid index into function table" +]; + +function assertTraps(trap, code) { + var threwException = true; + try { + if (typeof code === 'function') { + code(); + } else { + eval(code); + } + threwException = false; + } catch (e) { + assertEquals("object", typeof e); + assertEquals(kTrapMsgs[trap], e.message); + // Success. + return; + } + throw new MjsUnitAssertionError("Did not trap, expected: " + + kTrapMsgs[trap]); +} + +function assertWasmThrows(value, code) { + assertEquals("number", typeof(value)); + try { + if (typeof code === 'function') { + code(); + } else { + eval(code); + } + } catch (e) { + assertEquals("number", typeof e); + assertEquals(value, e); + // Success. + return; + } + throw new MjsUnitAssertionError("Did not throw at all, expected: " + + value); +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js new file mode 100644 index 0000000..0d8c698 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
@@ -0,0 +1,581 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Used for encoding f32 and double constants to bits. +let __buffer = new ArrayBuffer(8); +let byte_view = new Int8Array(__buffer); +let f32_view = new Float32Array(__buffer); +let f64_view = new Float64Array(__buffer); + +class Binary extends Array { + emit_u8(val) { + this.push(val); + } + + emit_u16(val) { + this.push(val & 0xff); + this.push((val >> 8) & 0xff); + } + + emit_u32(val) { + this.push(val & 0xff); + this.push((val >> 8) & 0xff); + this.push((val >> 16) & 0xff); + this.push((val >> 24) & 0xff); + } + + emit_u32v(val) { + while (true) { + let v = val & 0xff; + val = val >>> 7; + if (val == 0) { + this.push(v); + break; + } + this.push(v | 0x80); + } + } + + emit_bytes(data) { + for (let i = 0; i < data.length; i++) { + this.push(data[i] & 0xff); + } + } + + emit_string(string) { + // When testing illegal names, we pass a byte array directly. + if (string instanceof Array) { + this.emit_u32v(string.length); + this.emit_bytes(string); + return; + } + + // This is the hacky way to convert a JavaScript string to a UTF8 encoded + // string only containing single-byte characters. + let string_utf8 = unescape(encodeURIComponent(string)); + this.emit_u32v(string_utf8.length); + for (let i = 0; i < string_utf8.length; i++) { + this.emit_u8(string_utf8.charCodeAt(i)); + } + } + + emit_header() { + this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3, + kWasmV0, kWasmV1, kWasmV2, kWasmV3); + } + + emit_section(section_code, content_generator) { + // Emit section name. + this.emit_u8(section_code); + // Emit the section to a temporary buffer: its full length isn't know yet. + let section = new Binary; + content_generator(section); + // Emit section length. + this.emit_u32v(section.length); + // Copy the temporary buffer. + this.push(...section); + } +} + +class WasmFunctionBuilder { + constructor(module, name, type_index) { + this.module = module; + this.name = name; + this.type_index = type_index; + this.body = []; + } + + exportAs(name) { + this.module.addExport(name, this.index); + return this; + } + + exportFunc() { + this.exportAs(this.name); + return this; + } + + addBody(body) { + for (let b of body) { + if (typeof b != 'number') throw new Error("invalid body"); + } + this.body = body; + // Automatically add the end for the function block to the body. + body.push(kExprEnd); + return this; + } + + addBodyWithEnd(body) { + this.body = body; + return this; + } + + addLocals(locals) { + this.locals = locals; + return this; + } + + end() { + return this.module; + } +} + +class WasmGlobalBuilder { + constructor(module, type, mutable) { + this.module = module; + this.type = type; + this.mutable = mutable; + this.init = 0; + } + + exportAs(name) { + this.module.exports.push({name: name, kind: kExternalGlobal, + index: this.index}); + return this; + } +} + +class WasmModuleBuilder { + constructor() { + this.types = []; + this.imports = []; + this.exports = []; + this.globals = []; + this.functions = []; + this.function_table = []; + this.function_table_length = 0; + this.function_table_inits = []; + this.segments = []; + this.explicit = []; + this.num_imported_funcs = 0; + this.num_imported_globals = 0; + return this; + } + + addStart(start_index) { + this.start_index = start_index; + return this; + } + + addMemory(min, max, exp) { + this.memory = {min: min, max: max, exp: exp}; + return this; + } + + addExplicitSection(bytes) { + this.explicit.push(bytes); + return this; + } + + stringToBytes(name) { + var result = new Binary(); + result.emit_u32v(name.length); + for (var i = 0; i < name.length; i++) { + result.emit_u8(name.charCodeAt(i)); + } + return result; + } + + addCustomSection(name, bytes) { + name = this.stringToBytes(name); + var length = new Binary(); + length.emit_u32v(name.length + bytes.length); + this.explicit.push([0, ...length, ...name, ...bytes]); + } + + addType(type) { + // TODO: canonicalize types? + this.types.push(type); + return this.types.length - 1; + } + + addGlobal(local_type, mutable) { + let glob = new WasmGlobalBuilder(this, local_type, mutable); + glob.index = this.globals.length + this.num_imported_globals; + this.globals.push(glob); + return glob; + } + + addFunction(name, type) { + let type_index = (typeof type) == "number" ? type : this.addType(type); + let func = new WasmFunctionBuilder(this, name, type_index); + func.index = this.functions.length + this.num_imported_funcs; + this.functions.push(func); + return func; + } + + addImport(module = "", name, type) { + let type_index = (typeof type) == "number" ? type : this.addType(type); + this.imports.push({module: module, name: name, kind: kExternalFunction, + type: type_index}); + return this.num_imported_funcs++; + } + + addImportedGlobal(module = "", name, type) { + let o = {module: module, name: name, kind: kExternalGlobal, type: type, + mutable: false} + this.imports.push(o); + return this.num_imported_globals++; + } + + addImportedMemory(module = "", name, initial = 0, maximum) { + let o = {module: module, name: name, kind: kExternalMemory, + initial: initial, maximum: maximum}; + this.imports.push(o); + return this; + } + + addImportedTable(module = "", name, initial, maximum) { + let o = {module: module, name: name, kind: kExternalTable, initial: initial, + maximum: maximum}; + this.imports.push(o); + } + + addExport(name, index) { + this.exports.push({name: name, kind: kExternalFunction, index: index}); + return this; + } + + addExportOfKind(name, kind, index) { + this.exports.push({name: name, kind: kind, index: index}); + return this; + } + + addDataSegment(addr, data, is_global = false) { + this.segments.push({addr: addr, data: data, is_global: is_global}); + return this.segments.length - 1; + } + + exportMemoryAs(name) { + this.exports.push({name: name, kind: kExternalMemory, index: 0}); + } + + addFunctionTableInit(base, is_global, array, is_import = false) { + this.function_table_inits.push({base: base, is_global: is_global, + array: array}); + if (!is_global) { + var length = base + array.length; + if (length > this.function_table_length && !is_import) { + this.function_table_length = length; + } + } + return this; + } + + appendToTable(array) { + return this.addFunctionTableInit(this.function_table.length, false, array); + } + + setFunctionTableLength(length) { + this.function_table_length = length; + return this; + } + + toArray(debug = false) { + let binary = new Binary; + let wasm = this; + + // Add header + binary.emit_header(); + + // Add type section + if (wasm.types.length > 0) { + if (debug) print("emitting types @ " + binary.length); + binary.emit_section(kTypeSectionCode, section => { + section.emit_u32v(wasm.types.length); + for (let type of wasm.types) { + section.emit_u8(kWasmFunctionTypeForm); + section.emit_u32v(type.params.length); + for (let param of type.params) { + section.emit_u8(param); + } + section.emit_u32v(type.results.length); + for (let result of type.results) { + section.emit_u8(result); + } + } + }); + } + + // Add imports section + if (wasm.imports.length > 0) { + if (debug) print("emitting imports @ " + binary.length); + binary.emit_section(kImportSectionCode, section => { + section.emit_u32v(wasm.imports.length); + for (let imp of wasm.imports) { + section.emit_string(imp.module); + section.emit_string(imp.name || ''); + section.emit_u8(imp.kind); + if (imp.kind == kExternalFunction) { + section.emit_u32v(imp.type); + } else if (imp.kind == kExternalGlobal) { + section.emit_u32v(imp.type); + section.emit_u8(imp.mutable); + } else if (imp.kind == kExternalMemory) { + var has_max = (typeof imp.maximum) != "undefined"; + section.emit_u8(has_max ? 1 : 0); // flags + section.emit_u32v(imp.initial); // initial + if (has_max) section.emit_u32v(imp.maximum); // maximum + } else if (imp.kind == kExternalTable) { + section.emit_u8(kWasmAnyFunctionTypeForm); + var has_max = (typeof imp.maximum) != "undefined"; + section.emit_u8(has_max ? 1 : 0); // flags + section.emit_u32v(imp.initial); // initial + if (has_max) section.emit_u32v(imp.maximum); // maximum + } else { + throw new Error("unknown/unsupported import kind " + imp.kind); + } + } + }); + } + + // Add functions declarations + let has_names = false; + let names = false; + if (wasm.functions.length > 0) { + if (debug) print("emitting function decls @ " + binary.length); + binary.emit_section(kFunctionSectionCode, section => { + section.emit_u32v(wasm.functions.length); + for (let func of wasm.functions) { + has_names = has_names || (func.name != undefined && + func.name.length > 0); + section.emit_u32v(func.type_index); + } + }); + } + + // Add function_table. + if (wasm.function_table_length > 0) { + if (debug) print("emitting table @ " + binary.length); + binary.emit_section(kTableSectionCode, section => { + section.emit_u8(1); // one table entry + section.emit_u8(kWasmAnyFunctionTypeForm); + section.emit_u8(1); + section.emit_u32v(wasm.function_table_length); + section.emit_u32v(wasm.function_table_length); + }); + } + + // Add memory section + if (wasm.memory != undefined) { + if (debug) print("emitting memory @ " + binary.length); + binary.emit_section(kMemorySectionCode, section => { + section.emit_u8(1); // one memory entry + section.emit_u32v(kResizableMaximumFlag); + section.emit_u32v(wasm.memory.min); + section.emit_u32v(wasm.memory.max); + }); + } + + // Add global section. + if (wasm.globals.length > 0) { + if (debug) print ("emitting globals @ " + binary.length); + binary.emit_section(kGlobalSectionCode, section => { + section.emit_u32v(wasm.globals.length); + for (let global of wasm.globals) { + section.emit_u8(global.type); + section.emit_u8(global.mutable); + if ((typeof global.init_index) == "undefined") { + // Emit a constant initializer. + switch (global.type) { + case kWasmI32: + section.emit_u8(kExprI32Const); + section.emit_u32v(global.init); + break; + case kWasmI64: + section.emit_u8(kExprI64Const); + section.emit_u32v(global.init); + break; + case kWasmF32: + section.emit_u8(kExprF32Const); + f32_view[0] = global.init; + section.emit_u8(byte_view[0]); + section.emit_u8(byte_view[1]); + section.emit_u8(byte_view[2]); + section.emit_u8(byte_view[3]); + break; + case kWasmF64: + section.emit_u8(kExprF64Const); + f64_view[0] = global.init; + section.emit_u8(byte_view[0]); + section.emit_u8(byte_view[1]); + section.emit_u8(byte_view[2]); + section.emit_u8(byte_view[3]); + section.emit_u8(byte_view[4]); + section.emit_u8(byte_view[5]); + section.emit_u8(byte_view[6]); + section.emit_u8(byte_view[7]); + break; + } + } else { + // Emit a global-index initializer. + section.emit_u8(kExprGetGlobal); + section.emit_u32v(global.init_index); + } + section.emit_u8(kExprEnd); // end of init expression + } + }); + } + + // Add export table. + var mem_export = (wasm.memory != undefined && wasm.memory.exp); + var exports_count = wasm.exports.length + (mem_export ? 1 : 0); + if (exports_count > 0) { + if (debug) print("emitting exports @ " + binary.length); + binary.emit_section(kExportSectionCode, section => { + section.emit_u32v(exports_count); + for (let exp of wasm.exports) { + section.emit_string(exp.name); + section.emit_u8(exp.kind); + section.emit_u32v(exp.index); + } + if (mem_export) { + section.emit_string("memory"); + section.emit_u8(kExternalMemory); + section.emit_u8(0); + } + }); + } + + // Add start function section. + if (wasm.start_index != undefined) { + if (debug) print("emitting start function @ " + binary.length); + binary.emit_section(kStartSectionCode, section => { + section.emit_u32v(wasm.start_index); + }); + } + + // Add table elements. + if (wasm.function_table_inits.length > 0) { + if (debug) print("emitting table @ " + binary.length); + binary.emit_section(kElementSectionCode, section => { + var inits = wasm.function_table_inits; + section.emit_u32v(inits.length); + section.emit_u8(0); // table index + + for (let init of inits) { + if (init.is_global) { + section.emit_u8(kExprGetGlobal); + } else { + section.emit_u8(kExprI32Const); + } + section.emit_u32v(init.base); + section.emit_u8(kExprEnd); + section.emit_u32v(init.array.length); + for (let index of init.array) { + section.emit_u32v(index); + } + } + }); + } + + // Add function bodies. + if (wasm.functions.length > 0) { + // emit function bodies + if (debug) print("emitting code @ " + binary.length); + binary.emit_section(kCodeSectionCode, section => { + section.emit_u32v(wasm.functions.length); + for (let func of wasm.functions) { + // Function body length will be patched later. + let local_decls = []; + let l = func.locals; + if (l != undefined) { + let local_decls_count = 0; + if (l.i32_count > 0) { + local_decls.push({count: l.i32_count, type: kWasmI32}); + } + if (l.i64_count > 0) { + local_decls.push({count: l.i64_count, type: kWasmI64}); + } + if (l.f32_count > 0) { + local_decls.push({count: l.f32_count, type: kWasmF32}); + } + if (l.f64_count > 0) { + local_decls.push({count: l.f64_count, type: kWasmF64}); + } + } + + let header = new Binary; + header.emit_u32v(local_decls.length); + for (let decl of local_decls) { + header.emit_u32v(decl.count); + header.emit_u8(decl.type); + } + + section.emit_u32v(header.length + func.body.length); + section.emit_bytes(header); + section.emit_bytes(func.body); + } + }); + } + + // Add data segments. + if (wasm.segments.length > 0) { + if (debug) print("emitting data segments @ " + binary.length); + binary.emit_section(kDataSectionCode, section => { + section.emit_u32v(wasm.segments.length); + for (let seg of wasm.segments) { + section.emit_u8(0); // linear memory index 0 + if (seg.is_global) { + // initializer is a global variable + section.emit_u8(kExprGetGlobal); + section.emit_u32v(seg.addr); + } else { + // initializer is a constant + section.emit_u8(kExprI32Const); + section.emit_u32v(seg.addr); + } + section.emit_u8(kExprEnd); + section.emit_u32v(seg.data.length); + section.emit_bytes(seg.data); + } + }); + } + + // Add any explicitly added sections + for (let exp of wasm.explicit) { + if (debug) print("emitting explicit @ " + binary.length); + binary.emit_bytes(exp); + } + + // Add function names. + if (has_names) { + if (debug) print("emitting names @ " + binary.length); + binary.emit_section(kUnknownSectionCode, section => { + section.emit_string("name"); + var count = wasm.functions.length + wasm.num_imported_funcs; + section.emit_u32v(count); + for (var i = 0; i < wasm.num_imported_funcs; i++) { + section.emit_u8(0); // empty string + section.emit_u8(0); // local names count == 0 + } + for (let func of wasm.functions) { + var name = func.name == undefined ? "" : func.name; + section.emit_string(name); + section.emit_u8(0); // local names count == 0 + } + }); + } + + return binary; + } + + toBuffer(debug = false) { + let bytes = this.toArray(debug); + let buffer = new ArrayBuffer(bytes.length); + let view = new Uint8Array(buffer); + for (let i = 0; i < bytes.length; i++) { + let val = bytes[i]; + if ((typeof val) == "string") val = val.charCodeAt(0); + view[i] = val | 0; + } + return buffer; + } + + instantiate(ffi) { + let module = new WebAssembly.Module(this.toBuffer()); + let instance = new WebAssembly.Instance(module, ffi); + return instance; + } +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html index b6b1d4fb..0e9c22a5 100644 --- a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html +++ b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html
@@ -2,11 +2,19 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="wasm_response_apis.js"></script> +<script src="../wasm/resources/wasm-constants.js"></script> +<script src="../wasm/resources/wasm-module-builder.js"></script> <script> promise_test(TestStreamedCompile, "test streamed compile"); promise_test(TestShortFormStreamedCompile, "test streamed compile with promise parameter"); promise_test(NegativeTestStreamedCompilePromise, "promise must produce a Response"); - promise_test(BlankResponse, "blank response"); - promise_test(FromArrayBuffer, "from array buffer"); - promise_test(FromInvalidArrayBuffer, "from an invalid array buffer"); + promise_test(CompileBlankResponse, "compile blank response"); + promise_test(InstantiateBlankResponse, "instantiate blank response"); + promise_test(CompileFromArrayBuffer, "compile from array buffer"); + promise_test(CompileFromInvalidArrayBuffer, "compile from an invalid array buffer"); + promise_test(TestStreamedInstantiate, "test streamed instantiate"); + promise_test(InstantiateFromArrayBuffer, "test regular instantiate"); + promise_test(InstantiateFromInvalidArrayBuffer, "test instantiate from invalid buffer"); + promise_test(TestShortFormStreamedInstantiate, "test streamed instantiate with promise parameter"); + promise_test(TestInstantiateComplexModule, "instantiate locally built module"); </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js index e8b8f921..26d6e3bd 100644 --- a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js +++ b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js
@@ -23,13 +23,19 @@ e => assert_true(e instanceof TypeError)); } -function BlankResponse() { +function CompileBlankResponse() { return WebAssembly.compile(new Response()) .then(assert_unreached, e => assert_true(e instanceof TypeError)); } -function FromArrayBuffer() { +function InstantiateBlankResponse() { + return WebAssembly.instantiate(new Response()) + .then(assert_unreached, + e => assert_true(e instanceof TypeError)); +} + +function CompileFromArrayBuffer() { return fetch(incrementer_url) .then(r => r.arrayBuffer()) .then(arr => new Response(arr)) @@ -38,7 +44,7 @@ .then(i => assert_equals(6, i.exports.increment(5))); } -function FromInvalidArrayBuffer() { +function CompileFromInvalidArrayBuffer() { var arr = new ArrayBuffer(10); var view = new Uint8Array(arr); for (var i = 0; i < view.length; ++i) view[i] = i; @@ -47,3 +53,89 @@ .then(assert_unreached, e => assert_true(e instanceof Error)); } + +function InstantiateFromInvalidArrayBuffer() { + var arr = new ArrayBuffer(10); + var view = new Uint8Array(arr); + for (var i = 0; i < view.length; ++i) view[i] = i; + + return WebAssembly.instantiate(new Response(arr)) + .then(assert_unreached, + e => assert_true(e instanceof Error)); +} + +function TestStreamedInstantiate() { + return fetch(incrementer_url) + .then(WebAssembly.instantiate) + .then(pair => assert_equals(5, pair.instance.exports.increment(4))); +} + +function InstantiateFromArrayBuffer() { + return fetch(incrementer_url) + .then(response => response.arrayBuffer()) + .then(WebAssembly.instantiate) + .then(pair => assert_equals(5, pair.instance.exports.increment(4))); +} + +function TestShortFormStreamedInstantiate() { + return WebAssembly.instantiate(fetch(incrementer_url)) + .then(pair => assert_equals(5, pair.instance.exports.increment(4))); +} + +function InstantiateFromInvalidArrayBuffer() { + var arr = new ArrayBuffer(10); + var view = new Uint8Array(arr); + for (var i = 0; i < view.length; ++i) view[i] = i; + + return WebAssembly.compile(new Response(arr)) + .then(assert_unreached, + e => assert_true(e instanceof Error)); +} + +function buildImportingModuleBytes() { + var builder = new WasmModuleBuilder(); + builder.addImportedMemory("", "memory", 1); + var kSig_v_i = makeSig([kWasmI32], []); + var signature = builder.addType(kSig_v_i); + builder.addImport("", "some_value", kSig_i_v); + builder.addImport("", "writer", signature); + + builder.addFunction("main", kSig_i_i) + .addBody([ + kExprGetLocal, 0, + kExprI32LoadMem, 0, 0, + kExprI32Const, 1, + kExprCallIndirect, signature, kTableZero, + kExprGetLocal,0, + kExprI32LoadMem,0, 0, + kExprCallFunction, 0, + kExprI32Add + ]).exportFunc(); + + // writer(mem[i]); + // return mem[i] + some_value(); + builder.addFunction("_wrap_writer", signature) + .addBody([ + kExprGetLocal, 0, + kExprCallFunction, 1]); + builder.appendToTable([2, 3]); + + var wire_bytes = builder.toBuffer(); + return wire_bytes; +} + +function TestInstantiateComplexModule() { + var mem_1 = new WebAssembly.Memory({initial: 1}); + var view_1 = new Int32Array(mem_1.buffer); + view_1[0] = 42; + var outval_1; + + var ffi = {"": + {some_value: () => 1, + writer: (x) => outval_1 = x , + memory: mem_1} + }; + return Promise.resolve(buildImportingModuleBytes()) + .then(b => WebAssembly.instantiate(b, ffi)) + .then(pair => assert_true(pair.instance instanceof WebAssembly.Instance)); +}
diff --git a/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html b/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html new file mode 100644 index 0000000..cc9ffdb --- /dev/null +++ b/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html
@@ -0,0 +1,72 @@ +<!DOCTYPE html> +<script src=../resources/testharness.js></script> +<script src=../resources/testharnessreport.js></script> +<script> + +// Check navigator.mediaCapabilities.encodingInfo() with some MIME types that +// should be recordable and a few that shouldn't. + +var createTestForContentType = function(mimeType, isSupported = true) { + async_test(function(t) { + const media = mimeType.split('/')[0]; + var queryParameters; + if (media == 'video') { + queryParameters = { + type : 'record', + video : { + contentType : mimeType, + width : 640, + height : 480, + bitrate : 10000, + framerate : 30 + } + }; + } else if (media == 'audio') { + queryParameters = {type : 'record', audio : {contentType : mimeType}}; + } else { + assert_unreached('Unsupported media type'); + } + + navigator.mediaCapabilities.encodingInfo(queryParameters) + .then((result) => { + assert_equals(isSupported, result.supported, mimeType + 'supported?'); + t.done(); + }) + .catch(() => { + assert_unreached('encodingInfo() ' + mimeType); + }); + }); +}; + +generate_tests(createTestForContentType, [ + [ 'video/webm', 'video/webm' ], + [ 'video/webm;codecs=vp8', 'video/webm;codecs=vp8' ], + [ 'video/webm;codecs=vp9', 'video/webm;codecs=vp9' ], + [ 'video/webm;codecs=VP8.0', 'video/webm;codecs=vp8.0' ], + [ 'video/webm;codecs=vp9.0', 'video/webm;codecs=vp9.0' ], + [ 'video/webm;codecs=h264', 'video/webm;codecs=h264' ], + [ 'video/webm;codecs=H264', 'video/webm;codecs=H264' ], + [ 'video/webm;codecs=avc1', 'video/webm;codecs=avc1' ], + // 'video/webm' supports audio codec specification, see + // http://www.webmproject.org/docs/container/ + [ 'video/webm;codecs=vp8,opus', 'video/webm;codecs=vp8,opus' ], + [ 'video/WEBM;codecs=VP8,OPUS', 'video/WEBM;codecs=VP8,OPUS' ], + [ 'video/webm;codecs=vp9,opus', 'video/webm;codecs=vp9,opus' ], + [ 'video/webm;codecs=vp8,vp9,opus', 'video/webm;codecs=vp8,vp9,opus' ], + [ 'video/webm;codecs=h264,opus', 'video/webm;codecs=h264,opus' ], + [ 'video/webm;codecs=h264,vp9,opus', 'video/webm;codecs=h264,vp9,opus' ], + // https://matroska.org/technical/specs/notes.html#MIME + [ 'video/x-matroska;codecs=vorbis', 'video/x-matroska;codecs=opus' ], + [ 'audio/webm', 'audio/webm' ], + [ 'audio/webm;codecs=opus', 'audio/webm;codecs=opus' ], + + // Rejected MIME types + [ 'video/invalid', 'video/invalid', false], + [ 'video/mpeg4', 'video/mpeg4', false], + [ 'video/webm;codecs=daala', 'video/webm;codecs=daala', false], + [ 'audio/invalid', 'audio/invalid', false], + [ 'audio/ogg', 'audio/ogg', false], + [ 'audio/webm;codecs=vorbis', 'audio/webm;codecs=vorbis', false], +]); + +</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt index 960ac76c..65655ea 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -3934,6 +3934,7 @@ attribute @@toStringTag method constructor method decodingInfo + method encodingInfo interface MediaCapabilitiesInfo attribute @@toStringTag getter powerEfficient
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 9027ab77..b4001d3 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3934,6 +3934,7 @@ attribute @@toStringTag method constructor method decodingInfo + method encodingInfo interface MediaCapabilitiesInfo attribute @@toStringTag getter powerEfficient
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py index f2e1f322..7b113eee 100644 --- a/third_party/WebKit/Source/build/scripts/json5_generator.py +++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -99,7 +99,7 @@ self._process(doc) @classmethod - def load_from_files(cls, file_paths, default_metadata, default_parameters=None): + def load_from_files(cls, file_paths, default_metadata=None, default_parameters=None): merged_doc = dict() for path in file_paths: assert path.endswith(".json5") @@ -198,8 +198,6 @@ def __init__(self, json5_files): self._outputs = {} # file_name -> generator self.gperf_path = None - if isinstance(json5_files, basestring): - json5_files = [json5_files] if json5_files: self.json5_file = Json5File.load_from_files(json5_files, self.default_metadata,
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py index c5ec411..533c0cf8 100755 --- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py +++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -17,66 +17,6 @@ from collections import OrderedDict -# Temporary hard-coded list of fields that are not CSS properties. -# TODO(shend): Put this into its own JSON5 file. -NONPROPERTIES = [ - {'name': 'IsLink', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - {'name': 'OriginalDisplay', 'field_template': 'keyword', 'default_value': 'inline', - 'type_name': 'EDisplay', 'inherited': False, 'independent': False, - 'keywords': [ - "inline", "block", "list-item", "inline-block", "table", "inline-table", "table-row-group", "table-header-group", - "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "-webkit-box", - "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "contents", "flow-root", "none" - ]}, - {'name': 'InsideLink', 'field_template': 'keyword', 'default_value': 'not-inside-link', - 'keywords': ['not-inside-link', 'inside-unvisited-link', 'inside-visited-link'], - 'inherited': True, 'independent': False}, - # Style can not be shared. - {'name': 'Unique', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - # Whether this style is affected by these pseudo-classes. - {'name': 'AffectedByFocus', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - {'name': 'AffectedByFocusWithin', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - {'name': 'AffectedByHover', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - {'name': 'AffectedByActive', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - {'name': 'AffectedByDrag', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - # A non-inherited property references a variable or @apply is used - {'name': 'HasVariableReferenceFromNonInheritedProperty', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - # Explicitly inherits a non-inherited property - {'name': 'HasExplicitlyInheritedProperties', 'field_template': 'monotonic_flag', - 'inherited': False, 'independent': False, 'default_value': False}, - # These are set if we used viewport or rem units when resolving a length. - # TODO(shend): HasViewportUnits should be a monotonic_flag. - {'name': 'HasViewportUnits', 'field_template': 'primitive', 'default_value': 'false', - 'type_name': 'bool', 'inherited': False, 'independent': False}, - {'name': 'HasRemUnits', 'field_template': 'monotonic_flag', 'default_value': 'false', - 'inherited': False, 'independent': False}, - # These properties only have generated storage, and their methods are handwritten in ComputedStyle. - # TODO(shend): Remove these fields and delete the 'storage_only' template. - {'name': 'EmptyState', 'field_template': 'storage_only', 'field_size': 1, 'default_value': 'false', - 'type_name': 'bool', 'inherited': False, 'independent': False}, - {'name': 'StyleType', 'field_template': 'storage_only', 'field_size': 6, 'default_value': '0', - 'type_name': 'PseudoId', 'inherited': False, 'independent': False}, - {'name': 'PseudoBits', 'field_template': 'storage_only', 'field_size': 8, 'default_value': 'kPseudoIdNone', - 'type_name': 'PseudoId', 'inherited': False, 'independent': False}, - # True if 'underline solid' is the only text decoration on this element. - {'name': 'HasSimpleUnderline', 'field_template': 'storage_only', 'field_size': 1, 'default_value': 'false', - 'type_name': 'bool', 'inherited': True, 'independent': False}, - # TODO(shend): vertical align is actually a CSS property, but since we don't support union fields - # which can be either a keyword or Length, this is generated as a nonproperty for now. Remove this - # once we can support union fields and groups. - {'name': 'VerticalAlign', 'field_template': 'storage_only', 'field_size': 4, 'default_value': 'EVerticalAlign::kBaseline', - 'type_name': 'EVerticalAlign', 'inherited': False, 'independent': False}, -] - - class Field(object): """ The generated ComputedStyle object is made up of a series of Fields. @@ -253,7 +193,7 @@ ) -def _create_fields(field_role, properties): +def _create_fields(properties): """ Create ComputedStyle fields from properties or nonproperties and return a list of Field objects. """ @@ -266,6 +206,8 @@ if property_['independent']: fields.append(_create_inherited_flag_field(property_)) + # TODO(shend): Get rid of the property/nonproperty field roles. + field_role = 'nonproperty' if property_['has_custom_compare_and_copy'] else 'property' fields.append(_create_field(field_role, property_)) return fields @@ -305,23 +247,9 @@ class ComputedStyleBaseWriter(make_style_builder.StyleBuilderWriter): - def __init__(self, json5_file_path): - super(ComputedStyleBaseWriter, self).__init__(json5_file_path) - self._outputs = { - 'ComputedStyleBase.h': self.generate_base_computed_style_h, - 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, - 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants, - } - - # TODO(shend): Remove this once we move NONPROPERTIES to its own JSON file, - # since the JSON5 reader will handle missing fields and defaults. - for property_ in NONPROPERTIES: - for parameter in self.json5_file.parameters: - if parameter not in property_: - property_[parameter] = None - - for property_ in NONPROPERTIES: - make_style_builder.apply_property_naming_defaults(property_) + def __init__(self, json5_file_paths): + # Read CSS properties + super(ComputedStyleBaseWriter, self).__init__([json5_file_paths[0]]) # Ignore shorthand properties for property_ in self._properties.values(): @@ -329,19 +257,33 @@ assert not property_['longhands'], \ "Shorthand '{}' cannot have a field_template.".format(property_['name']) - property_values = [value for value in self._properties.values() if not value['longhands']] + css_properties = [value for value in self._properties.values() if not value['longhands']] - for property_ in property_values: - # Override the type name when field_type_path is specified - if property_['field_type_path']: - property_['type_name'] = property_['field_type_path'].split('/')[-1] + for property_ in css_properties: + # All CSS properties that are generated do not have custom comparison and copy logic. + property_['has_custom_compare_and_copy'] = False # CSS properties are not allowed to explicitly specify their field_size. property_['field_size'] = None - self._generated_enums = _create_enums(property_values + NONPROPERTIES) + # Read extra fields using the parameter specification from the CSS properties file. + extra_fields = json5_generator.Json5File.load_from_files( + [json5_file_paths[1]], + default_parameters=self.json5_file.parameters + ).name_dictionaries - all_fields = (_create_fields('property', property_values) + - _create_fields('nonproperty', NONPROPERTIES)) + for property_ in extra_fields: + make_style_builder.apply_property_naming_defaults(property_) + + all_properties = css_properties + extra_fields + + # Override the type name when field_type_path is specified + for property_ in all_properties: + if property_['field_type_path']: + property_['type_name'] = property_['field_type_path'].split('/')[-1] + + self._generated_enums = _create_enums(all_properties) + + all_fields = _create_fields(all_properties) # Separate the normal fields from the bit fields bit_fields = [field for field in all_fields if field.is_bit_field] @@ -378,8 +320,12 @@ for field in bucket: self._fields.append(field) - self._include_paths = _get_include_paths(property_values + NONPROPERTIES) - + self._include_paths = _get_include_paths(all_properties) + self._outputs = { + 'ComputedStyleBase.h': self.generate_base_computed_style_h, + 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, + 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants, + } @template_expander.use_jinja('ComputedStyleBase.h.tmpl') def generate_base_computed_style_h(self):
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py index 1fd786a..c092ae9 100755 --- a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py +++ b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
@@ -35,12 +35,12 @@ class CSSPropertyAPIWriter(StyleBuilderWriter): def __init__(self, json5_file_paths): - super(CSSPropertyAPIWriter, self).__init__(json5_file_paths[0]) + super(CSSPropertyAPIWriter, self).__init__([json5_file_paths[0]]) # TODO(aazzam): Move the logic for loading CSSPropertyAPIMethods.json5 into a new class APIMethodsWriter(). assert len(json5_file_paths) == 2,\ 'CSSPropertyAPIWriter requires 2 input json5 files files, got {}.'.format(len(json5_file_paths)) - self.css_property_api_methods = Json5File.load_from_files([json5_file_paths[1]], {}, {}) + self.css_property_api_methods = Json5File.load_from_files([json5_file_paths[1]]) self._outputs = { 'CSSPropertyDescriptor.cpp': self.generate_property_descriptor_cpp,
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index 575e0d43..8997ff4 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -410,6 +410,7 @@ css_properties("make_core_generated_computed_style_base") { script = "../build/scripts/make_computed_style_base.py" + in_files = [ "css/ComputedStyleExtraFields.json5" ] other_inputs = [ "../build/scripts/templates/fields/field.tmpl", "../build/scripts/templates/fields/base.tmpl",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 new file mode 100644 index 0000000..eccee69b --- /dev/null +++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -0,0 +1,168 @@ +{ +// This file specifies fields in ComputedStyle that we would like to +// generate, but are not CSS properties. + + parameters: { + // - field_size + // Number of bits needed to store this field. Only used for storage_only + // fields. If specified, the field will be stored as bit field. Otherwise + // it will be stored as a normal data member. + field_size: { + valid_type: "int", + }, + + // If the field has_custom_compare_and_copy, then it does not appear in + // ComputedStyle::operator== and ComputedStyle::CopyNonInheritedFromCached. + has_custom_compare_and_copy: { + default: false, + }, + + // The rest is the same as CSSProperties.json5, but the only relevant ones in + // this file are: + // name, field_template, field_type_path, default_value, type_name, keyword, + // inherited + }, + + data: [ + { + name: "IsLink", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + { + name: "OriginalDisplay", + field_template: "keyword", + default_value: "inline", + type_name: "EDisplay", + keywords: [ + "inline", "block", "list-item", "inline-block", "table", "inline-table", "table-row-group", "table-header-group", + "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "-webkit-box", + "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "contents", "flow-root", "none", + ], + has_custom_compare_and_copy: true, + }, + { + name: "InsideLink", + field_template: "keyword", + default_value: "not-inside-link", + keywords: ["not-inside-link", "inside-unvisited-link", "inside-visited-link"], + inherited: true, + has_custom_compare_and_copy: true, + }, + // Style can not be shared. + { + name: "Unique", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + // Whether this style is affected by these pseudo-classes. + { + name: "AffectedByFocus", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + { + name: "AffectedByFocusWithin", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + { + name: "AffectedByHover", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + { + name: "AffectedByActive", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + { + name: "AffectedByDrag", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + // A non-inherited property references a variable or @apply is used + { + name: "HasVariableReferenceFromNonInheritedProperty", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + // Explicitly inherits a non-inherited property + { + name: "HasExplicitlyInheritedProperties", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + // These are set if we used viewport or rem units when resolving a length. + // TODO(shend): HasViewportUnits should be a monotonic_flag. + { + name: "HasViewportUnits", + field_template: "primitive", + default_value: "false", + type_name: "bool", + has_custom_compare_and_copy: true, + }, + { + name: "HasRemUnits", + field_template: "monotonic_flag", + default_value: "false", + has_custom_compare_and_copy: true, + }, + // These properties only have generated storage, and their methods are handwritten in ComputedStyle. + // TODO(shend): Remove these fields and delete the 'storage_only' template. + { + name: "EmptyState", + field_template: "storage_only", + field_size: 1, + default_value: "false", + type_name: "bool", + has_custom_compare_and_copy: true, + }, + { + name: "StyleType", + field_template: "storage_only", + field_size: 6, + default_value: "0", + type_name: "PseudoId", + has_custom_compare_and_copy: true, + }, + { + name: "PseudoBits", + field_template: "storage_only", + field_size: 8, + default_value: "kPseudoIdNone", + type_name: "PseudoId", + has_custom_compare_and_copy: true, + }, + // True if 'underline solid' is the only text decoration on this element. + { + name: "HasSimpleUnderline", + field_template: "storage_only", + field_size: 1, + default_value: "false", + type_name: "bool", + inherited: true, + has_custom_compare_and_copy: true, + }, + // TODO(shend): vertical align is actually a CSS property, but since we don't support union fields + // which can be either a keyword or Length, this is generated as a nonproperty for now. Remove this + // once we can support union fields and groups. + { + name: "VerticalAlign", + field_template: "storage_only", + field_size: 4, + default_value: "EVerticalAlign::kBaseline", + type_name: "EVerticalAlign", + has_custom_compare_and_copy: true, + }, + ], +}
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp index c66e3fb..eb950da 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
@@ -265,7 +265,7 @@ if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() && next_state == kInCompositingUpdate) return true; - if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() && next_state == kInPrePaint) return true; break; @@ -281,7 +281,7 @@ if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() && next_state == kInCompositingUpdate) return true; - if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() && next_state == kInPrePaint) return true; break;
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp index 89546cd..ab4370b6 100644 --- a/third_party/WebKit/Source/core/frame/Deprecation.cpp +++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -409,7 +409,7 @@ "removal and may be removed no earlier than %s. If you depend on it, " "please see https://www.chromestatus.com/features/5654810086866944 " "for more details.", - milestoneString(M60)); + milestoneString(M62)); case UseCounter::kV8IDBFactory_WebkitGetDatabaseNames_Method: return willBeRemoved("indexedDB.webkitGetDatabaseNames()", M60,
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index 7c67bcc..683424a8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1853,7 +1853,7 @@ } void SetSubtreeNeedsPaintPropertyUpdate() { bitfields_.SetSubtreeNeedsPaintPropertyUpdate(true); - bitfields_.SetNeedsPaintPropertyUpdate(true); + SetNeedsPaintPropertyUpdate(); } bool SubtreeNeedsPaintPropertyUpdate() const { return bitfields_.SubtreeNeedsPaintPropertyUpdate();
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp index e1beee3..b099b184 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -198,10 +198,11 @@ EXPECT_TRUE(object->BackgroundChangedSinceLastPaintInvalidation()); object->SetNeedsPaintPropertyUpdate(); EXPECT_TRUE(object->NeedsPaintPropertyUpdate()); + EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate()); object->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true); EXPECT_TRUE(object->DescendantNeedsPaintPropertyUpdate()); - ScopedSlimmingPaintV2ForTest enable_s_pv2(true); + ScopedSlimmingPaintInvalidationForTest enable_sp_invalidation(true); GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint); object->GetMutableForPainting().ClearPaintFlags(); @@ -215,6 +216,21 @@ EXPECT_FALSE(object->DescendantNeedsPaintPropertyUpdate()); } +TEST_F(LayoutObjectTest, SubtreeNeedsPaintPropertyUpdate) { + LayoutObject* object = GetDocument().body()->GetLayoutObject(); + object->SetSubtreeNeedsPaintPropertyUpdate(); + EXPECT_TRUE(object->SubtreeNeedsPaintPropertyUpdate()); + EXPECT_TRUE(object->NeedsPaintPropertyUpdate()); + EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate()); + + ScopedSlimmingPaintInvalidationForTest enable_sp_invalidation(true); + GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint); + object->GetMutableForPainting().ClearPaintFlags(); + + EXPECT_FALSE(object->SubtreeNeedsPaintPropertyUpdate()); + EXPECT_FALSE(object->NeedsPaintPropertyUpdate()); +} + TEST_F(LayoutObjectTest, NeedsPaintOffsetAndVisualRectUpdate) { LayoutObject* object = GetDocument().body()->GetLayoutObject(); LayoutObject* parent = object->Parent();
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp index 1858f56..0ec5372 100644 --- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp +++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp
@@ -8,9 +8,13 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromiseResolver.h" #include "bindings/core/v8/ScriptState.h" +#include "core/dom/DOMException.h" #include "modules/media_capabilities/MediaCapabilitiesInfo.h" +#include "modules/media_capabilities/MediaConfiguration.h" #include "modules/media_capabilities/MediaDecodingConfiguration.h" +#include "modules/media_capabilities/MediaEncodingConfiguration.h" #include "public/platform/Platform.h" +#include "public/platform/WebMediaRecorderHandler.h" #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesClient.h" #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h" #include "public/platform/modules/media_capabilities/WebMediaConfiguration.h" @@ -65,12 +69,9 @@ } WebMediaConfiguration ToWebMediaConfiguration( - const MediaDecodingConfiguration& configuration) { + const MediaConfiguration& configuration) { WebMediaConfiguration web_configuration; - // |type| is mandatory. - DCHECK(configuration.hasType()); - if (configuration.hasAudio()) { web_configuration.audio_configuration = ToWebAudioConfiguration(configuration.audio()); @@ -94,6 +95,9 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); + // |type| is mandatory. + DCHECK(configuration.hasType()); + Platform::Current()->MediaCapabilitiesClient()->DecodingInfo( ToWebMediaConfiguration(configuration), WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( @@ -102,6 +106,36 @@ return promise; } +ScriptPromise MediaCapabilities::encodingInfo( + ScriptState* script_state, + const MediaEncodingConfiguration& configuration) { + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise promise = resolver->Promise(); + + if (!configuration.hasVideo() && !configuration.hasAudio()) { + resolver->Reject(DOMException::Create( + kSyntaxError, + "The configuration dictionary has neither |video| nor |audio| " + "specified and needs at least one of them.")); + return promise; + } + + WebMediaRecorderHandler* handler = + Platform::Current()->CreateMediaRecorderHandler(); + if (!handler) { + resolver->Reject(DOMException::Create( + kInvalidStateError, + "Platform error: could not create MediaRecorderHandler.")); + return promise; + } + + handler->EncodingInfo( + ToWebMediaConfiguration(configuration), + WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( + resolver)); + return promise; +} + DEFINE_TRACE(MediaCapabilities) {} } // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h index 35d0781..d482adb 100644 --- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h +++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h
@@ -11,6 +11,7 @@ namespace blink { class MediaDecodingConfiguration; +class MediaEncodingConfiguration; class ScriptPromise; class ScriptState; @@ -23,6 +24,7 @@ MediaCapabilities(); ScriptPromise decodingInfo(ScriptState*, const MediaDecodingConfiguration&); + ScriptPromise encodingInfo(ScriptState*, const MediaEncodingConfiguration&); DECLARE_VIRTUAL_TRACE(); };
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl index 75e767e4..21def833 100644 --- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl +++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl
@@ -9,6 +9,6 @@ RuntimeEnabled=MediaCapabilities ] interface MediaCapabilities { [CallWith=ScriptState] Promise<MediaCapabilitiesInfo> decodingInfo(MediaDecodingConfiguration configuration); - - // TODO(mcasas): Implement encodingInfo(), https://crbug.com/709181 + [CallWith=ScriptState] Promise<MediaCapabilitiesInfo> encodingInfo( + MediaEncodingConfiguration configuration); };
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl b/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl new file mode 100644 index 0000000..d433c362 --- /dev/null +++ b/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl
@@ -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. + +// https://wicg.github.io/media-capabilities/#dictdef-mediaencodingconfiguration + +enum MediaEncodingType { + "record", + // TODO(mcasas): Implement other types https://crbug.com/709181 +}; + +dictionary MediaEncodingConfiguration : MediaConfiguration{ + required MediaEncodingType type; +};
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index c68f3ec..7a09ee1 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -448,6 +448,7 @@ "media_capabilities/AudioConfiguration.idl", "media_capabilities/MediaConfiguration.idl", "media_capabilities/MediaDecodingConfiguration.idl", + "media_capabilities/MediaEncodingConfiguration.idl", "media_capabilities/VideoConfiguration.idl", "mediarecorder/BlobEventInit.idl", "mediarecorder/MediaRecorderOptions.idl", @@ -798,6 +799,8 @@ "$blink_modules_output_dir/media_capabilities/MediaConfiguration.h", "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.cpp", "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.h", + "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.cpp", + "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.h", "$blink_modules_output_dir/media_capabilities/VideoConfiguration.cpp", "$blink_modules_output_dir/media_capabilities/VideoConfiguration.h", "$blink_modules_output_dir/mediarecorder/BlobEventInit.cpp",
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py index 52e82e0..97dd87e25 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py
@@ -80,7 +80,7 @@ def _add_base_manifest_to_mock_filesystem(self, filesystem): webkit_finder = WebKitFinder(filesystem) - external_dir = webkit_finder.path_from_webkit_base('LayoutTests', 'external') + external_dir = webkit_finder.path_from_layout_tests('external') filesystem.maybe_make_directory(filesystem.join(external_dir, 'wpt')) manifest_base_path = filesystem.join(external_dir, 'WPT_BASE_MANIFEST.json')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py index fa5a775..7b4a97c2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py
@@ -82,6 +82,9 @@ self._chromium_base = None self._depot_tools = None + # TODO(tkent): Make this private. We should use functions for + # sub-directories in order to make the code robust against directory + # structure changes. def webkit_base(self): """Returns the absolute path to the top of the WebKit tree. @@ -102,21 +105,33 @@ self._chromium_base = self._filesystem.dirname(self._filesystem.dirname(self.webkit_base())) return self._chromium_base + # TODO(tkent): Make this private. We should use functions for + # sub-directories in order to make the code robust against directory + # structure changes. def path_from_webkit_base(self, *comps): return self._filesystem.join(self.webkit_base(), *comps) def path_from_chromium_base(self, *comps): return self._filesystem.join(self.chromium_base(), *comps) + def path_from_blink_source(self, *comps): + return self._filesystem.join(self._filesystem.join(self.webkit_base(), 'Source'), *comps) + def path_to_script(self, script_name): """Returns the relative path to the script from the top of the WebKit tree.""" # This is intentionally relative in order to force callers to consider what # their current working directory is (and change to the top of the tree if necessary). return self._filesystem.join('Tools', 'Scripts', script_name) + def path_from_tools_scripts(self, *comps): + return self._filesystem.join(self._filesystem.join(self.webkit_base(), 'Tools', 'Scripts'), *comps) + def layout_tests_dir(self): return self.path_from_webkit_base('LayoutTests') + def path_from_layout_tests(self, *comps): + return self._filesystem.join(self.layout_tests_dir(), *comps) + def perf_tests_dir(self): return self.path_from_webkit_base('PerformanceTests')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py index 035ba59..7920da4 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py
@@ -145,7 +145,7 @@ def test_fails(self, tests): extra_args = ['--debug'] if self.is_debug else [] - path_to_run_webkit_tests = self.webkit_finder.path_from_webkit_base('Tools', 'Scripts', 'run-webkit-tests') + path_to_run_webkit_tests = self.webkit_finder.path_from_tools_scripts('run-webkit-tests') output = self.executive.popen( [path_to_run_webkit_tests, '--child-processes', '1', '--order', 'none', '--no-retry', '--no-show-results', '--verbose'] + extra_args + tests, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py index 3f3aabf..cbcb91b2c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -537,7 +537,7 @@ _log.error("Upload failed: %s", err) def _copy_results_html_file(self, destination_path): - base_dir = self._port.path_from_webkit_base('LayoutTests', 'fast', 'harness') + base_dir = self._webkit_finder.path_from_layout_tests('fast', 'harness') results_file = self._filesystem.join(base_dir, 'results.html') # Note that the results.html template file won't exist when we're using a MockFileSystem during unit tests, # so make sure it exists before we try to copy it.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py index f679d17..62c523a 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -33,6 +33,7 @@ import logging import re +from webkitpy.common.webkit_finder import WebKitFinder from webkitpy.layout_tests.models.test_configuration import TestConfigurationConverter _log = logging.getLogger(__name__) @@ -1095,8 +1096,10 @@ return REBASELINE in self._model.get_expectations(test) def _shorten_filename(self, filename): - if filename.startswith(self._port.path_from_webkit_base()): - return self._port.host.filesystem.relpath(filename, self._port.path_from_webkit_base()) + finder = WebKitFinder(self._port.host.filesystem) + # TODO(tkent): Can we use path_from_layout_tests() instead? + if filename.startswith(finder.path_from_webkit_base()): + return self._port.host.filesystem.relpath(filename, finder.path_from_webkit_base()) return filename def _report_warnings(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py index dbcd2ea84..821ac4f3 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -178,7 +178,7 @@ self._dump_reader = None # FIXME: prettypatch.py knows this path; it should not be copied here. - self._pretty_patch_path = self.path_from_webkit_base('Tools', 'Scripts', 'webkitruby', 'PrettyPatch', 'prettify.rb') + self._pretty_patch_path = self._webkit_finder.path_from_tools_scripts('webkitruby', 'PrettyPatch', 'prettify.rb') self._pretty_patch_available = None if not hasattr(options, 'configuration') or not options.configuration: @@ -869,13 +869,10 @@ self._filesystem.write_binary_file(baseline_path, data) # TODO(qyearsley): Update callers to create a finder and call it instead - # of these next five routines (which should be protected). + # of these next three routines (which should be protected). def webkit_base(self): return self._webkit_finder.webkit_base() - def path_from_webkit_base(self, *comps): - return self._webkit_finder.path_from_webkit_base(*comps) - def path_from_chromium_base(self, *comps): return self._webkit_finder.path_from_chromium_base(*comps) @@ -1029,7 +1026,7 @@ return self._build_path('resources', 'inspector') def apache_config_directory(self): - return self.path_from_webkit_base('Tools', 'Scripts', 'apache_config') + return self._webkit_finder.path_from_tools_scripts('apache_config') def default_results_directory(self): """Returns the absolute path to the default place to store the test results."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py index 063792b..69e1fe0 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py
@@ -32,6 +32,7 @@ import sys import time +from webkitpy.common.webkit_finder import WebKitFinder from webkitpy.layout_tests.servers import server_base @@ -55,7 +56,7 @@ time_str = time.strftime('%d%b%Y-%H%M%S') log_file_name = _WS_LOG_PREFIX + time_str self._error_log = self._filesystem.join(self._output_dir, log_file_name + '-err.txt') - pywebsocket_base = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty') + pywebsocket_base = WebKitFinder(self._filesystem).path_from_tools_scripts('webkitpy', 'thirdparty') pywebsocket_script = self._filesystem.join(pywebsocket_base, 'mod_pywebsocket', 'standalone.py') self._start_cmd = [
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py index c0efd2a0..e77cca1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
@@ -7,6 +7,7 @@ import datetime import logging +from webkitpy.common.webkit_finder import WebKitFinder from webkitpy.layout_tests.servers import server_base @@ -32,8 +33,9 @@ fs = self._filesystem self._pid_file = fs.join(self._runtime_path, '%s.pid' % self._name) - path_to_thirdparty = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty') - path_to_wpt_support = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty', 'wpt') + finder = WebKitFinder(fs) + path_to_thirdparty = finder.path_from_tools_scripts('webkitpy', 'thirdparty') + path_to_wpt_support = finder.path_from_tools_scripts('webkitpy', 'thirdparty', 'wpt') path_to_wpt_root = fs.join(path_to_wpt_support, 'wpt') path_to_wpt_config = fs.join(path_to_wpt_support, 'wpt.config.json') path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.layout_tests_dir(), 'external', 'wpt'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py index 365d4278..475be32 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
@@ -76,10 +76,10 @@ executive = Executive() env = os.environ.copy() env['PYTHONPATH'] = os.pathsep.join([ - wkf.path_from_webkit_base('Tools', 'Scripts'), - wkf.path_from_webkit_base('Source', 'build', 'scripts'), - wkf.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty'), - wkf.path_from_webkit_base('Source', 'bindings', 'scripts'), + wkf.path_from_tools_scripts(), + wkf.path_from_blink_source('build', 'scripts'), + wkf.path_from_tools_scripts('webkitpy', 'thirdparty'), + wkf.path_from_blink_source('bindings', 'scripts'), wkf.path_from_chromium_base('build', 'android'), wkf.path_from_chromium_base('third_party', 'catapult', 'devil'), wkf.path_from_chromium_base('third_party', 'pymock'),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py index 7e9e6fe8..77007531 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py
@@ -55,7 +55,7 @@ test_list += each + ' ' filesystem = FileSystem() webkit_finder = WebKitFinder(filesystem) - script_dir = webkit_finder.path_from_webkit_base('Tools', 'Scripts') + script_dir = webkit_finder.path_from_tools_scripts() executable_path = script_dir + '/run-webkit-tests' cmd = 'python ' + executable_path + ' --no-show-results ' cmd += test_list
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py index 9b56ada..5320390 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py
@@ -9,7 +9,7 @@ @memoized def absolute_chromium_wpt_dir(host): finder = WebKitFinder(host.filesystem) - return finder.path_from_webkit_base('LayoutTests', 'external', 'wpt') + return finder.path_from_layout_tests('external', 'wpt') @memoized
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py index d701aac..3da67383 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
@@ -18,7 +18,7 @@ def read_owner_map(self): """Reads the W3CImportExpectations file and returns a map of directories to owners.""" - input_path = self.finder.path_from_webkit_base('LayoutTests', 'W3CImportExpectations') + input_path = self.finder.path_from_layout_tests('W3CImportExpectations') input_contents = self.filesystem.read_text_file(input_path) self.owner_map = self.lines_to_owner_map(input_contents.splitlines())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py index 6b865bf5..5fedc8a 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py
@@ -61,7 +61,7 @@ self.filesystem = self.host.filesystem self.webkit_finder = WebKitFinder(self.filesystem) self._webkit_root = self.webkit_finder.webkit_base() - self.layout_tests_dir = self.webkit_finder.path_from_webkit_base('LayoutTests') + self.layout_tests_dir = self.webkit_finder.layout_tests_dir() self.destination_directory = self.filesystem.normpath( self.filesystem.join( self.layout_tests_dir, @@ -142,7 +142,7 @@ def find_paths_to_skip(self): paths_to_skip = set() port = self.host.port_factory.get() - w3c_import_expectations_path = self.webkit_finder.path_from_webkit_base('LayoutTests', 'W3CImportExpectations') + w3c_import_expectations_path = self.webkit_finder.path_from_layout_tests('W3CImportExpectations') w3c_import_expectations = self.filesystem.read_text_file(w3c_import_expectations_path) parser = TestExpectationParser(port, all_tests=(), is_lint_mode=False) expectation_lines = parser.parse(w3c_import_expectations_path, w3c_import_expectations)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py index 26ce818..c64588e1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -67,7 +67,7 @@ # TODO(qyearsley): Simplify this to use LocalWPT.fetch when csswg-test # is merged into web-platform-tests (crbug.com/706118). - temp_repo_path = self.path_from_webkit_base(dest_dir_name) + temp_repo_path = self.finder.path_from_webkit_base(dest_dir_name) _log.info('Cloning repo: %s', repo_url) _log.info('Local path: %s', temp_repo_path) self.run(['git', 'clone', repo_url, temp_repo_path]) @@ -139,7 +139,7 @@ _log.warning('Checkout has local commits; aborting. Use --allow-local-commits to allow this.') return False - if self.fs.exists(self.path_from_webkit_base(WPT_DEST_NAME)): + if self.fs.exists(self.finder.path_from_webkit_base(WPT_DEST_NAME)): _log.warning('WebKit/%s exists; aborting.', WPT_DEST_NAME) return False @@ -178,8 +178,8 @@ ('testharness.js', 'resources'), ] for filename, wpt_subdir in resources_to_copy_from_wpt: - source = self.path_from_webkit_base('LayoutTests', 'external', WPT_DEST_NAME, wpt_subdir, filename) - destination = self.path_from_webkit_base('LayoutTests', 'resources', filename) + source = self.finder.path_from_layout_tests('external', WPT_DEST_NAME, wpt_subdir, filename) + destination = self.finder.path_from_layout_tests('resources', filename) self.copyfile(source, destination) self.run(['git', 'add', destination]) @@ -222,7 +222,7 @@ _, show_ref_output = self.run(['git', 'show-ref', 'origin/master'], cwd=temp_repo_path) master_commitish = show_ref_output.split()[0] - dest_path = self.path_from_webkit_base('LayoutTests', 'external', dest_dir_name) + dest_path = self.finder.path_from_layout_tests('external', dest_dir_name) self._clear_out_dest_path(dest_path) _log.info('Importing the tests.') @@ -312,18 +312,15 @@ self.fs.copyfile(source, destination) def remove(self, *comps): - dest = self.path_from_webkit_base(*comps) + dest = self.finder.path_from_webkit_base(*comps) _log.debug('rm %s', dest) self.fs.remove(dest) def rmtree(self, *comps): - dest = self.path_from_webkit_base(*comps) + dest = self.finder.path_from_webkit_base(*comps) _log.debug('rm -fr %s', dest) self.fs.rmtree(dest) - def path_from_webkit_base(self, *comps): - return self.finder.path_from_webkit_base(*comps) - def do_auto_update(self): """Attempts to upload a CL, make any required adjustments, and commit.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py index ff48742d..ec6009c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -91,8 +91,8 @@ def ensure_manifest(host): """Checks whether the manifest exists, and then generates it if necessary.""" finder = WebKitFinder(host.filesystem) - manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'wpt', 'MANIFEST.json') - base_manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'WPT_BASE_MANIFEST.json') + manifest_path = finder.path_from_layout_tests('external', 'wpt', 'MANIFEST.json') + base_manifest_path = finder.path_from_layout_tests('external', 'WPT_BASE_MANIFEST.json') if not host.filesystem.exists(base_manifest_path): _log.error('Manifest base not found at "%s".', base_manifest_path) @@ -102,7 +102,7 @@ _log.debug('Manifest not found, copying from base "%s".', base_manifest_path) host.filesystem.copyfile(base_manifest_path, manifest_path) - wpt_path = manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'wpt') + wpt_path = manifest_path = finder.path_from_layout_tests('external', 'wpt') WPTManifest.generate_manifest(host, wpt_path) @staticmethod @@ -110,7 +110,7 @@ """Generates MANIFEST.json on the specified directory.""" executive = host.executive finder = WebKitFinder(host.filesystem) - manifest_exec_path = finder.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty', 'wpt', 'wpt', 'manifest') + manifest_exec_path = finder.path_from_tools_scripts('webkitpy', 'thirdparty', 'wpt', 'wpt', 'manifest') cmd = ['python', manifest_exec_path, '--work', '--tests-root', dest_path] _log.debug('Running command: %s', ' '.join(cmd))
diff --git a/third_party/WebKit/public/platform/WebMediaRecorderHandler.h b/third_party/WebKit/public/platform/WebMediaRecorderHandler.h index fe9c90c..ddc064a1 100644 --- a/third_party/WebKit/public/platform/WebMediaRecorderHandler.h +++ b/third_party/WebKit/public/platform/WebMediaRecorderHandler.h
@@ -5,11 +5,16 @@ #ifndef WebMediaRecorderHandler_h #define WebMediaRecorderHandler_h +#include <memory> + #include "WebCommon.h" +#include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h" + namespace blink { class WebMediaRecorderHandlerClient; +struct WebMediaConfiguration; class WebMediaStream; class WebString; @@ -41,6 +46,12 @@ const WebString& codecs) { return false; } + + // Implements WICG Media Capabilities encodingInfo() call for local encoding. + // https://wicg.github.io/media-capabilities/#media-capabilities-interface + virtual void EncodingInfo( + const WebMediaConfiguration&, + std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks>) {} }; } // namespace blink
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 1d5b079..956a7f6 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -37462,6 +37462,24 @@ </summary> </histogram> +<histogram name="Net.ResourceDispatcherHost.OutstandingRequests.PerProcess" + units="requests"> + <owner>xunjieli@chromium.org</owner> + <summary> + The largest number of outstanding requests that are handled by the resource + dispatcher host for a single process. + </summary> +</histogram> + +<histogram name="Net.ResourceDispatcherHost.OutstandingRequests.Total" + units="requests"> + <owner>xunjieli@chromium.org</owner> + <summary> + The largest number of outstanding requests that are handled by the resource + dispatcher host across all processes. + </summary> +</histogram> + <histogram name="Net.ResourceLoader.ExpectedContentSizeResult" enum="ResourceLoaderExpectedContentSizeResult"> <owner>maksim.sisov@intel.com</owner>
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py index 5c0c2b5..f37ce44 100644 --- a/tools/perf/benchmarks/media.py +++ b/tools/perf/benchmarks/media.py
@@ -114,7 +114,7 @@ test = media.Media tag = 'android' page_set = page_sets.ToughVideoCasesPageSet - options = {'story_tag_filter_exclude': 'is_4k,is_50fps,theora'} + options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} @classmethod def ShouldDisable(cls, possible_browser): @@ -136,7 +136,7 @@ Will eventually replace MediaAndroidToughVideoCases class.""" tag = 'android' - options = {'story_tag_filter_exclude': 'is_4k,is_50fps,theora'} + options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} @classmethod def ShouldDisable(cls, possible_browser):
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py index 6ff629b15..bc7bb6f7 100644 --- a/tools/perf/page_sets/tough_video_cases.py +++ b/tools/perf/page_sets/tough_video_cases.py
@@ -12,7 +12,6 @@ 'vorbis', 'opus', # Video codecs: - 'theora', 'h264', 'vp8', 'vp9', @@ -56,20 +55,6 @@ label='seek_cold') -class Page1(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page1, self).__init__( - url='file://tough_video_cases/video.html?src=crowd.wav&type=audio', - page_set=page_set, - tags=['pcm', 'audio_only']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - class Page2(ToughVideoCasesPage): def __init__(self, page_set): @@ -84,23 +69,6 @@ self.PlayAction(action_runner) -class Page3(ToughVideoCasesPage): - - # Note that ffprobe reports about this file: - # "[ogg @ 0x31a3ba0] Broken file, keyframe not correctly marked." - # This media file should probably be removed or replaced. - def __init__(self, page_set): - super(Page3, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080.ogv', - page_set=page_set, - tags=['is_50fps', 'theora', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - class Page4(ToughVideoCasesPage): def __init__(self, page_set): @@ -115,34 +83,6 @@ self.PlayAction(action_runner) -class Page5(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page5, self).__init__( - url='file://tough_video_cases/video.html?src=crowd2160.ogv', - page_set=page_set, - tags=['is_4k', 'is_50fps', 'theora', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page6(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page6, self).__init__( - url='file://tough_video_cases/video.html?src=crowd2160.webm', - page_set=page_set, - tags=['is_4k', 'is_50fps', 'vp8', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - class Page7(ToughVideoCasesPage): def __init__(self, page_set): @@ -171,34 +111,6 @@ self.PlayAction(action_runner) -class Page9(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page9, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.ogv', - page_set=page_set, - tags=['theora', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page10(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page10, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.webm', - page_set=page_set, - tags=['vp8', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - class Page11(ToughVideoCasesPage): def __init__(self, page_set): @@ -297,20 +209,6 @@ self.PlayAction(action_runner) -class Page18(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page18, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.ogv', - page_set=page_set, - tags=['is_4k', 'theora', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - class Page19(ToughVideoCasesPage): def __init__(self, page_set): @@ -339,37 +237,6 @@ self.SeekBeforeAndAfterPlayhead(action_runner) -class Page21(ToughVideoCasesPage): - - # Note that ffprobe reports about this file: - # "[ogg @ 0x39adba0] Broken file, keyframe not correctly marked." - # This media file should probably be removed or replaced. - def __init__(self, page_set): - super(Page21, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.ogv', - page_set=page_set, - tags=['theora', 'vorbis', 'audio_video']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page22(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page22, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.webm', - page_set=page_set, - tags=['vp8', 'vorbis', 'audio_video']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - class Page23(ToughVideoCasesPage): def __init__(self, page_set): @@ -426,20 +293,6 @@ self.SeekBeforeAndAfterPlayhead(action_runner) -class Page27(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page27, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.ogv', - page_set=page_set, - tags=['is_4k', 'theora', 'vorbis', 'audio_video']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - class Page30(ToughVideoCasesPage): def __init__(self, page_set): @@ -574,22 +427,6 @@ def RunPageInteractions(self, action_runner): self.PlayAction(action_runner) -class Page40(ToughVideoCasesPage): - - # Note that ffprobe reports about this file: - # "[ogg @ 0x31a3ba0] Broken file, keyframe not correctly marked." - # This media file should probably be removed or replaced. - def __init__(self, page_set): - super(Page40, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080.ogv&canvas=true', - page_set=page_set, - tags=['is_50fps', 'theora', 'vorbis', 'audio_video']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - class ToughVideoCasesPageSet(story.StorySet): """ Description: Video Stack Perf pages that report time_to_play and many other @@ -603,16 +440,10 @@ # This may be a non-issue because we plan to merge these two page sets back # together and use tags to allow teams to filter which pages they want. - self.AddStory(Page1(self)) self.AddStory(Page2(self)) - self.AddStory(Page3(self)) self.AddStory(Page4(self)) - self.AddStory(Page5(self)) - self.AddStory(Page6(self)) self.AddStory(Page7(self)) self.AddStory(Page8(self)) - self.AddStory(Page9(self)) - self.AddStory(Page10(self)) self.AddStory(Page11(self)) self.AddStory(Page12(self)) self.AddStory(Page13(self)) @@ -620,7 +451,6 @@ self.AddStory(Page15(self)) self.AddStory(Page16(self)) self.AddStory(Page17(self)) - self.AddStory(Page18(self)) self.AddStory(Page30(self)) self.AddStory(Page32(self)) self.AddStory(Page34(self)) @@ -628,7 +458,6 @@ self.AddStory(Page37(self)) self.AddStory(Page38(self)) self.AddStory(Page39(self)) - self.AddStory(Page40(self)) class ToughVideoCasesExtraPageSet(story.StorySet): @@ -641,13 +470,10 @@ self.AddStory(Page19(self)) self.AddStory(Page20(self)) - self.AddStory(Page21(self)) - self.AddStory(Page22(self)) self.AddStory(Page23(self)) self.AddStory(Page24(self)) self.AddStory(Page25(self)) self.AddStory(Page26(self)) - self.AddStory(Page27(self)) self.AddStory(Page31(self)) self.AddStory(Page33(self)) self.AddStory(Page35(self))
diff --git a/tools/perf/page_sets/tough_video_cases/bear.webm.sha1 b/tools/perf/page_sets/tough_video_cases/bear.webm.sha1 deleted file mode 100644 index 211df9c..0000000 --- a/tools/perf/page_sets/tough_video_cases/bear.webm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -4415d9927e32855eb21c371827d0427c354f2588 \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1 b/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1 deleted file mode 100644 index 065dc001..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1 +++ /dev/null
@@ -1 +0,0 @@ -17d48d36b74701799999a0d3dc25a67038c75caa \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1 deleted file mode 100644 index 75f8866..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c3da321e4f90e9aa61d1237058af65131f027854 \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1 b/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1 deleted file mode 100644 index f079662c..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c9651176398fa86932adac7fe534eb018f7862ce \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1 deleted file mode 100644 index 0cb63a3..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -c1e3675623f4d2cd72e56dcaad432e0e8cc26d9c \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1 deleted file mode 100644 index ff29292..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1 +++ /dev/null
@@ -1 +0,0 @@ -59ea02c91615499cfa15026de0c3c56821105d44 \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1 deleted file mode 100644 index c2724f3..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -470f851bcde812871187afbdf79db1625c8c48fc \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1 deleted file mode 100644 index 6bc8d0d5..0000000 --- a/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -7ff870ce89dee7718455ba2eb8e1b0d835fc0d56 \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1 deleted file mode 100644 index beadbd9..0000000 --- a/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ba612b13ab5b8c555beac5c30d825bbfb58fdb11 \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1 deleted file mode 100644 index e33446c..0000000 --- a/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e6e14183467faad4f5800b02ca8c9deb5d59191f \ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1 b/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1 deleted file mode 100644 index cd93dcf..0000000 --- a/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -091425493334b1505aa0fe5b1d0f36fd1d8ac8bb \ No newline at end of file
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index dea73f5..e0686043 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -138,6 +138,7 @@ "cocoa/tool_tip_base_view.h", "cocoa/tool_tip_base_view.mm", "cocoa/touch_bar_forward_declarations.h", + "cocoa/touch_bar_forward_declarations.mm", "cocoa/tracking_area.h", "cocoa/tracking_area.mm", "cocoa/underlay_opengl_hosting_window.h",
diff --git a/ui/base/cocoa/touch_bar_forward_declarations.h b/ui/base/cocoa/touch_bar_forward_declarations.h index 0e33268..ce03c6aa 100644 --- a/ui/base/cocoa/touch_bar_forward_declarations.h +++ b/ui/base/cocoa/touch_bar_forward_declarations.h
@@ -6,9 +6,11 @@ #define UI_BASE_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_ // Once Chrome no longer supports OSX 10.12.0, this file can be deleted. - +#import <AppKit/AppKit.h> #import <Foundation/Foundation.h> +#include "ui/base/ui_base_export.h" + #if !defined(MAC_OS_X_VERSION_10_12_1) #pragma clang assume_nonnull begin @@ -24,12 +26,6 @@ typedef NSString* NSTouchBarItemIdentifier; typedef NSString* NSTouchBarCustomizationIdentifier; -static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFixedSpaceSmall = - @"NSTouchBarItemIdentifierFixedSpaceSmall"; - -static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFlexibleSpace = - @"NSTouchBarItemIdentifierFlexibleSpace"; - @interface NSTouchBar : NSObject<NSCoding> - (instancetype)init NS_DESIGNATED_INITIALIZER; @@ -97,8 +93,6 @@ makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier; @end -#pragma clang assume_nonnull end - #elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1 // When compiling against the 10.12.1 SDK or later, just provide forward @@ -116,4 +110,14 @@ #endif // MAC_OS_X_VERSION_10_12_1 +extern "C" { +#if !defined(MAC_OS_X_VERSION_10_12_1) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1 +UI_BASE_EXPORT extern NSString* const NSTouchBarItemIdentifierFixedSpaceSmall; +UI_BASE_EXPORT extern NSString* const NSTouchBarItemIdentifierFlexibleSpace; +#endif // MAC_OS_X_VERSION_10_12_1 +} // extern "C" + +#pragma clang assume_nonnull end + #endif // UI_BASE_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
diff --git a/ui/base/cocoa/touch_bar_forward_declarations.mm b/ui/base/cocoa/touch_bar_forward_declarations.mm new file mode 100644 index 0000000..1df5a9b --- /dev/null +++ b/ui/base/cocoa/touch_bar_forward_declarations.mm
@@ -0,0 +1,13 @@ +// 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/cocoa/touch_bar_forward_declarations.h" + +#if !defined(MAC_OS_X_VERSION_10_12_1) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1 +NSString* const NSTouchBarItemIdentifierFixedSpaceSmall = + @"NSTouchBarItemIdentifierFixedSpaceSmall"; +NSString* const NSTouchBarItemIdentifierFlexibleSpace = + @"NSTouchBarItemIdentifierFlexibleSpace"; +#endif // MAC_OS_X_VERSION_10_12_1